算法题,如何在python和opencv中求一个角码包围的像素个数
Algorithmic problem, how to find the number of pixels bordered by an angle code in python and opencv
新手来了,我正在研究python/opencv关于空间关系的问题,我需要从一个点P找到范围(0,alpha)内的白色像素的数量,你有吗一个想法如何去做或者有什么工具。
这里有两张图很好地描述了我的问题
我的原始二值图像
从给定的点 p,我需要计算角度所形成的形状内有多少白色像素
如果有任何我可以实现的算法解决方案或任何opencv函数请告诉我。
大声笑,@Fiver 在我完成示例编码之前就开始了。好吧,这就是我所做的。
我创建了一组三个点(原始点、一个远离右侧的点和一个与给定角度匹配的旋转点)。
我用那三个点画了两条线。我使用 copyMakeBorder 在图像外部创建一个方形边缘,以使用我绘制的线条创建一个闭合形状。然后我使用 findContours 并且我知道我将获得三个轮廓(角度 == 0 时除外,但让我们忽略它)。
第一个轮廓将是整个矩形,因为我选择了树层次结构(它是父级)。在两个子轮廓中,我将它们分成大的和小的,然后根据给定的角度选择我想要制作面具的那个。
标记图像
只是面具
注意:当 angle == 0 或 abs(angle) == 180 时,此方法将失败。当 angle == 0 时,只有两个轮廓,因此代码会崩溃。当 abs(angle) == 180 时,它会任意选择一个轮廓。
import cv2
import math
import numpy as np
# turns a list into an int tuple
def tup(point):
return (int(point[0]), int(point[1]));
# translate a point
def translate2D(point, target, sign):
point[0] += target[0] * sign;
point[1] += target[1] * sign;
# rotate a point
def rotate2D(point, deg):
# unpack
x, y = point;
rads = math.radians(deg);
# trig
rcos = math.cos(rads);
rsin = math.sin(rads);
# rotate
point[0] = x * rcos - y * rsin;
point[1] = x * rsin + y * rcos;
# load image
img = cv2.imread("blub.png");
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);
# point and angle
point = [100, 150];
angle = -60; # negative is counter-clockwise
# create projection
xproj = [point[0] + img.shape[1], point[1]];
rot = xproj[:];
translate2D(rot, point, -1);
rotate2D(rot, angle);
translate2D(rot, point, 1);
# create copy and draw lines
mask = np.zeros(img.shape[:2], np.uint8);
mask = cv2.line(mask, tup(point), tup(xproj), (255), 1);
mask = cv2.line(mask, tup(point), tup(rot), (255), 1);
border = 1;
mask = cv2.copyMakeBorder(mask, border, border, border, border, cv2.BORDER_CONSTANT, None, (255));
# contours (should always be 3 unless 0 degrees)
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
print(len(contours));
# compare two children contours
one, two = contours[1:];
if cv2.contourArea(one) > cv2.contourArea(two):
big = one;
small = two;
else:
big = two;
small = one;
# check which one we should draw
if abs(angle) >= 180:
con = small;
else:
con = big;
cv2.drawContours(gray, [con], -1, (0), -1);
mask = cv2.inRange(gray, 100, 255);
# draw visual
img[mask == 255] = (0,0,200);
img = cv2.line(img, tup(point), tup(xproj), (0,255,0), 1);
img = cv2.line(img, tup(point), tup(rot), (0,255,0), 1);
# count
print("White Pixels: " + str(np.count_nonzero(mask)));
# show
cv2.imshow("mask", mask);
cv2.imshow("blub", img);
cv2.waitKey(0);
编辑:
如果您想将其推广到两点+一个角度的情况(不仅仅是沿 x 轴投影),我们可以使用相同的算法,但只需将 x 投影点替换为沿 向量。
import cv2
import math
import numpy as np
# extends a p2 along its line
def extend(p1, p2, proj_length):
# get unit vector
dx = p2[0] - p1[0];
dy = p2[1] - p1[1];
dist = math.sqrt(dx*dx + dy*dy);
dx /= dist;
dy /= dist;
# project
dx *= proj_length;
dy *= proj_length;
return [dx, dy];
# turns a list into an int tuple
def tup(point):
return (int(point[0]), int(point[1]));
# translate a point
def translate2D(point, target, sign):
point[0] += target[0] * sign;
point[1] += target[1] * sign;
# rotate a point
def rotate2D(point, deg):
# unpack
x, y = point;
rads = math.radians(deg);
# trig
rcos = math.cos(rads);
rsin = math.sin(rads);
# rotate
point[0] = x * rcos - y * rsin;
point[1] = x * rsin + y * rcos;
# load image
img = cv2.imread("blub.png");
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);
# get image resolution
h, w = img.shape[:2];
# point and angle
point = [100, 150];
angle = -60; # negative is counter-clockwise
# second point
p2 = [150, 90];
# create projection
# xproj = [point[0] + img.shape[1], point[1]];
projection = extend(point, p2, h * w);
rot = projection[:];
translate2D(rot, point, -1);
rotate2D(rot, angle);
translate2D(rot, point, 1);
# create copy and draw lines
mask = np.zeros(img.shape[:2], np.uint8);
mask = cv2.line(mask, tup(point), tup(projection), (255), 1);
mask = cv2.line(mask, tup(point), tup(rot), (255), 1);
border = 1;
mask = cv2.copyMakeBorder(mask, border, border, border, border, cv2.BORDER_CONSTANT, None, (255));
# contours (should always be 3 unless 0 degrees)
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
print(len(contours));
# compare two children contours
one, two = contours[1:];
if cv2.contourArea(one) > cv2.contourArea(two):
big = one;
small = two;
else:
big = two;
small = one;
# check which one we should draw
if abs(angle) >= 180:
con = small;
else:
con = big;
cv2.drawContours(gray, [con], -1, (0), -1);
mask = cv2.inRange(gray, 100, 255);
# draw visual
img[mask == 255] = (0,0,200);
cv2.line(img, tup(point), tup(projection), (0,255,0), 1);
cv2.line(img, tup(point), tup(rot), (0,255,0), 1);
cv2.circle(img, tup(point), 3, (255,255,0), -1);
cv2.circle(img, tup(p2), 3, (255,255,0), -1);
# count
print("White Pixels: " + str(np.count_nonzero(mask)));
# show
cv2.imshow("mask", mask);
cv2.imshow("blub", img);
cv2.waitKey(0);
新手来了,我正在研究python/opencv关于空间关系的问题,我需要从一个点P找到范围(0,alpha)内的白色像素的数量,你有吗一个想法如何去做或者有什么工具。
这里有两张图很好地描述了我的问题
我的原始二值图像
从给定的点 p,我需要计算角度所形成的形状内有多少白色像素
如果有任何我可以实现的算法解决方案或任何opencv函数请告诉我。
大声笑,@Fiver 在我完成示例编码之前就开始了。好吧,这就是我所做的。
我创建了一组三个点(原始点、一个远离右侧的点和一个与给定角度匹配的旋转点)。
我用那三个点画了两条线。我使用 copyMakeBorder 在图像外部创建一个方形边缘,以使用我绘制的线条创建一个闭合形状。然后我使用 findContours 并且我知道我将获得三个轮廓(角度 == 0 时除外,但让我们忽略它)。
第一个轮廓将是整个矩形,因为我选择了树层次结构(它是父级)。在两个子轮廓中,我将它们分成大的和小的,然后根据给定的角度选择我想要制作面具的那个。
标记图像
只是面具
注意:当 angle == 0 或 abs(angle) == 180 时,此方法将失败。当 angle == 0 时,只有两个轮廓,因此代码会崩溃。当 abs(angle) == 180 时,它会任意选择一个轮廓。
import cv2
import math
import numpy as np
# turns a list into an int tuple
def tup(point):
return (int(point[0]), int(point[1]));
# translate a point
def translate2D(point, target, sign):
point[0] += target[0] * sign;
point[1] += target[1] * sign;
# rotate a point
def rotate2D(point, deg):
# unpack
x, y = point;
rads = math.radians(deg);
# trig
rcos = math.cos(rads);
rsin = math.sin(rads);
# rotate
point[0] = x * rcos - y * rsin;
point[1] = x * rsin + y * rcos;
# load image
img = cv2.imread("blub.png");
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);
# point and angle
point = [100, 150];
angle = -60; # negative is counter-clockwise
# create projection
xproj = [point[0] + img.shape[1], point[1]];
rot = xproj[:];
translate2D(rot, point, -1);
rotate2D(rot, angle);
translate2D(rot, point, 1);
# create copy and draw lines
mask = np.zeros(img.shape[:2], np.uint8);
mask = cv2.line(mask, tup(point), tup(xproj), (255), 1);
mask = cv2.line(mask, tup(point), tup(rot), (255), 1);
border = 1;
mask = cv2.copyMakeBorder(mask, border, border, border, border, cv2.BORDER_CONSTANT, None, (255));
# contours (should always be 3 unless 0 degrees)
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
print(len(contours));
# compare two children contours
one, two = contours[1:];
if cv2.contourArea(one) > cv2.contourArea(two):
big = one;
small = two;
else:
big = two;
small = one;
# check which one we should draw
if abs(angle) >= 180:
con = small;
else:
con = big;
cv2.drawContours(gray, [con], -1, (0), -1);
mask = cv2.inRange(gray, 100, 255);
# draw visual
img[mask == 255] = (0,0,200);
img = cv2.line(img, tup(point), tup(xproj), (0,255,0), 1);
img = cv2.line(img, tup(point), tup(rot), (0,255,0), 1);
# count
print("White Pixels: " + str(np.count_nonzero(mask)));
# show
cv2.imshow("mask", mask);
cv2.imshow("blub", img);
cv2.waitKey(0);
编辑:
如果您想将其推广到两点+一个角度的情况(不仅仅是沿 x 轴投影),我们可以使用相同的算法,但只需将 x 投影点替换为沿
import cv2
import math
import numpy as np
# extends a p2 along its line
def extend(p1, p2, proj_length):
# get unit vector
dx = p2[0] - p1[0];
dy = p2[1] - p1[1];
dist = math.sqrt(dx*dx + dy*dy);
dx /= dist;
dy /= dist;
# project
dx *= proj_length;
dy *= proj_length;
return [dx, dy];
# turns a list into an int tuple
def tup(point):
return (int(point[0]), int(point[1]));
# translate a point
def translate2D(point, target, sign):
point[0] += target[0] * sign;
point[1] += target[1] * sign;
# rotate a point
def rotate2D(point, deg):
# unpack
x, y = point;
rads = math.radians(deg);
# trig
rcos = math.cos(rads);
rsin = math.sin(rads);
# rotate
point[0] = x * rcos - y * rsin;
point[1] = x * rsin + y * rcos;
# load image
img = cv2.imread("blub.png");
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);
# get image resolution
h, w = img.shape[:2];
# point and angle
point = [100, 150];
angle = -60; # negative is counter-clockwise
# second point
p2 = [150, 90];
# create projection
# xproj = [point[0] + img.shape[1], point[1]];
projection = extend(point, p2, h * w);
rot = projection[:];
translate2D(rot, point, -1);
rotate2D(rot, angle);
translate2D(rot, point, 1);
# create copy and draw lines
mask = np.zeros(img.shape[:2], np.uint8);
mask = cv2.line(mask, tup(point), tup(projection), (255), 1);
mask = cv2.line(mask, tup(point), tup(rot), (255), 1);
border = 1;
mask = cv2.copyMakeBorder(mask, border, border, border, border, cv2.BORDER_CONSTANT, None, (255));
# contours (should always be 3 unless 0 degrees)
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
print(len(contours));
# compare two children contours
one, two = contours[1:];
if cv2.contourArea(one) > cv2.contourArea(two):
big = one;
small = two;
else:
big = two;
small = one;
# check which one we should draw
if abs(angle) >= 180:
con = small;
else:
con = big;
cv2.drawContours(gray, [con], -1, (0), -1);
mask = cv2.inRange(gray, 100, 255);
# draw visual
img[mask == 255] = (0,0,200);
cv2.line(img, tup(point), tup(projection), (0,255,0), 1);
cv2.line(img, tup(point), tup(rot), (0,255,0), 1);
cv2.circle(img, tup(point), 3, (255,255,0), -1);
cv2.circle(img, tup(p2), 3, (255,255,0), -1);
# count
print("White Pixels: " + str(np.count_nonzero(mask)));
# show
cv2.imshow("mask", mask);
cv2.imshow("blub", img);
cv2.waitKey(0);