算法题,如何在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);