Python 获取围绕中心像素的像素周长

Python 获取围绕中心像素的像素周长,python,opencv,trigonometry,Python,Opencv,Trigonometry,我试图得到一个围绕中心像素的像素圈。也就是说,就像关键点探测器的工作速度一样,我想在给定半径的情况下得到它周围的周长像素。不管我怎么搞不懂数学,我从理论上知道如何用三角学得到它。也就是说,我可以使用for循环并以15度进行迭代。我知道三角形斜边的长度是半径,我知道角度 有没有关于如何获得给定像素周围像素周长的建议 假设img是您的图像,半径是圆的半径,x,y是您要聚焦的中心的坐标 可通过以下方式获得焦点\u img offset = math.ceil(radius * math.sqrt(2)

我试图得到一个围绕中心像素的像素圈。也就是说,就像关键点探测器的工作速度一样,我想在给定半径的情况下得到它周围的周长像素。不管我怎么搞不懂数学,我从理论上知道如何用三角学得到它。也就是说,我可以使用for循环并以15度进行迭代。我知道三角形斜边的长度是半径,我知道角度

有没有关于如何获得给定像素周围像素周长的建议


假设
img
是您的图像,
半径
是圆的半径,
x,y
是您要聚焦的中心的坐标

可通过以下方式获得
焦点\u img

offset = math.ceil(radius * math.sqrt(2))
focus_img = img[y-offset:y+offset, x-offset:x+offset]

假设
img
是您的图像,
radius
是圆的半径,
x,y
是您要聚焦的中心的坐标

可通过以下方式获得
焦点\u img

offset = math.ceil(radius * math.sqrt(2))
focus_img = img[y-offset:y+offset, x-offset:x+offset]
公式是:

(x-cx)**2 + (y-cy)**2 = r**2
其中cx和cy是圆心,x和y是要测试的坐标。。。现在我们可以迭代x,得到y,公式如下:

y = sqrt(r**2 - (x-cx)**2) + cy
x = cos(radians) * radius + cx
y = sin(radians) * radius + cy
另一种方法是迭代360度并计算x和y,然后添加偏移(中心),如下所示:

y = sqrt(r**2 - (x-cx)**2) + cy
x = cos(radians) * radius + cx
y = sin(radians) * radius + cy
第二个版本在我的测试中给了我一个更完整的循环。以下是我的python测试脚本:

import numpy as np
import cv2
import math

img = np.zeros((480, 640, 1), dtype="uint8")
img2 = np.zeros((480, 640, 1), dtype="uint8")

center = (200, 200)
radius = 100

x = np.arange(center[0] - radius, center[0]+radius+1)
y_off = np.sqrt(radius**2 - (x - center[0]) **2)
y1 = np.int32(np.round(center[1] + y_off))
y2 = np.int32(np.round(center[1] - y_off))
img[y1, x] = 255
img[y2, x] = 255


degrees = np.arange(360)
x = np.int32(np.round(np.cos(degrees) * radius)) + center[0]
y = np.int32(np.round(np.sin(degrees) * radius)) + center[1]
img2[y,x] = 255


cv2.imshow("First method", img)
cv2.imshow("Second method", img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:

方法1

方法2

还有第三种方法。。。在半径x半径的圆周围取一个方框,用上面给出的圆公式计算每个点,如果为真,则它是一个圆点。。。然而,这是很好的画整个圆,因为你有整数,很可能没有多少点是相等的


更新:

只是一个小提示,请确保您的点在图像中,在上面的示例中,如果您将中心置于0,0,它将在每个角绘制1/4的圆,因为它考虑从阵列的末端开始的负值

要删除重复项,可以尝试以下代码:

c = np.unique(np.array(list(zip(y,x))), axis=0  )
img2[c[:,0], c[:,1]] = 255
公式是:

(x-cx)**2 + (y-cy)**2 = r**2
其中cx和cy是圆心,x和y是要测试的坐标。。。现在我们可以迭代x,得到y,公式如下:

y = sqrt(r**2 - (x-cx)**2) + cy
x = cos(radians) * radius + cx
y = sin(radians) * radius + cy
另一种方法是迭代360度并计算x和y,然后添加偏移(中心),如下所示:

y = sqrt(r**2 - (x-cx)**2) + cy
x = cos(radians) * radius + cx
y = sin(radians) * radius + cy
第二个版本在我的测试中给了我一个更完整的循环。以下是我的python测试脚本:

import numpy as np
import cv2
import math

img = np.zeros((480, 640, 1), dtype="uint8")
img2 = np.zeros((480, 640, 1), dtype="uint8")

center = (200, 200)
radius = 100

x = np.arange(center[0] - radius, center[0]+radius+1)
y_off = np.sqrt(radius**2 - (x - center[0]) **2)
y1 = np.int32(np.round(center[1] + y_off))
y2 = np.int32(np.round(center[1] - y_off))
img[y1, x] = 255
img[y2, x] = 255


degrees = np.arange(360)
x = np.int32(np.round(np.cos(degrees) * radius)) + center[0]
y = np.int32(np.round(np.sin(degrees) * radius)) + center[1]
img2[y,x] = 255


cv2.imshow("First method", img)
cv2.imshow("Second method", img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:

方法1

方法2

还有第三种方法。。。在半径x半径的圆周围取一个方框,用上面给出的圆公式计算每个点,如果为真,则它是一个圆点。。。然而,这是很好的画整个圆,因为你有整数,很可能没有多少点是相等的


更新:

只是一个小提示,请确保您的点在图像中,在上面的示例中,如果您将中心置于0,0,它将在每个角绘制1/4的圆,因为它考虑从阵列的末端开始的负值

要删除重复项,可以尝试以下代码:

c = np.unique(np.array(list(zip(y,x))), axis=0  )
img2[c[:,0], c[:,1]] = 255

只需在遮罩上画一个圆圈:

In [27]: mask = np.zeros((9, 9), dtype=np.uint8)

In [28]: cv2.circle(mask, center=(4, 4), radius=4, color=255, thickness=1)
Out[28]:
array([[  0,   0,   0,   0, 255,   0,   0,   0,   0],
       [  0,   0, 255, 255,   0, 255, 255,   0,   0],
       [  0, 255,   0,   0,   0,   0,   0, 255,   0],
       [  0, 255,   0,   0,   0,   0,   0, 255,   0],
       [255,   0,   0,   0,   0,   0,   0,   0, 255],
       [  0, 255,   0,   0,   0,   0,   0, 255,   0],
       [  0, 255,   0,   0,   0,   0,   0, 255,   0],
       [  0,   0, 255, 255,   0, 255, 255,   0,   0],
       [  0,   0,   0,   0, 255,   0,   0,   0,   0]], dtype=uint8)
现在你可以用它来索引你喜欢的图像。例如,这里有一个随机图像:

In [33]: img
Out[33]:
array([[ 88, 239, 212, 160,  89,  85, 249, 242,  88],
       [ 47, 230, 206, 206,  63, 143, 152,  67,  58],
       [162, 212,   0, 213, 208, 169, 228,  14, 229],
       [230,  45, 103, 201, 188, 231,  80, 122, 131],
       [159,  31, 148, 158,  73, 215, 152, 158, 235],
       [213, 177, 148, 237,  92, 115, 152, 188, 223],
       [234,  67, 141, 173,  14,  18, 242, 208, 147],
       [ 53, 194, 229, 141,  37, 215, 230, 167,  82],
       [ 72,  78, 152,  76, 230, 128, 137,  25, 168]], dtype=uint8)
以下是周长上的值:

In [34]: img[np.nonzero(mask)]
Out[34]:
array([ 89, 206, 206, 143, 152, 212,  14,  45, 122, 159, 235, 177, 188,
        67, 208, 229, 141, 215, 230, 230], dtype=uint8)
将圆周长处的图像值设置为0:

In [35]: img[np.nonzero(mask)] = 0

In [36]: img
Out[36]:
array([[ 88, 239, 212, 160,   0,  85, 249, 242,  88],
       [ 47, 230,   0,   0,  63,   0,   0,  67,  58],
       [162,   0,   0, 213, 208, 169, 228,   0, 229],
       [230,   0, 103, 201, 188, 231,  80,   0, 131],
       [  0,  31, 148, 158,  73, 215, 152, 158,   0],
       [213,   0, 148, 237,  92, 115, 152,   0, 223],
       [234,   0, 141, 173,  14,  18, 242,   0, 147],
       [ 53, 194,   0,   0,  37,   0,   0, 167,  82],
       [ 72,  78, 152,  76,   0, 128, 137,  25, 168]], dtype=uint8)
您也可以轻松获得坐标:

In [56]: np.where(mask)
Out[56]:
(array([0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8]),
 array([4, 2, 3, 5, 6, 1, 7, 1, 7, 0, 8, 1, 7, 1, 7, 2, 3, 5, 6, 4]))

只需在遮罩上画一个圆圈:

In [27]: mask = np.zeros((9, 9), dtype=np.uint8)

In [28]: cv2.circle(mask, center=(4, 4), radius=4, color=255, thickness=1)
Out[28]:
array([[  0,   0,   0,   0, 255,   0,   0,   0,   0],
       [  0,   0, 255, 255,   0, 255, 255,   0,   0],
       [  0, 255,   0,   0,   0,   0,   0, 255,   0],
       [  0, 255,   0,   0,   0,   0,   0, 255,   0],
       [255,   0,   0,   0,   0,   0,   0,   0, 255],
       [  0, 255,   0,   0,   0,   0,   0, 255,   0],
       [  0, 255,   0,   0,   0,   0,   0, 255,   0],
       [  0,   0, 255, 255,   0, 255, 255,   0,   0],
       [  0,   0,   0,   0, 255,   0,   0,   0,   0]], dtype=uint8)
现在你可以用它来索引你喜欢的图像。例如,这里有一个随机图像:

In [33]: img
Out[33]:
array([[ 88, 239, 212, 160,  89,  85, 249, 242,  88],
       [ 47, 230, 206, 206,  63, 143, 152,  67,  58],
       [162, 212,   0, 213, 208, 169, 228,  14, 229],
       [230,  45, 103, 201, 188, 231,  80, 122, 131],
       [159,  31, 148, 158,  73, 215, 152, 158, 235],
       [213, 177, 148, 237,  92, 115, 152, 188, 223],
       [234,  67, 141, 173,  14,  18, 242, 208, 147],
       [ 53, 194, 229, 141,  37, 215, 230, 167,  82],
       [ 72,  78, 152,  76, 230, 128, 137,  25, 168]], dtype=uint8)
以下是周长上的值:

In [34]: img[np.nonzero(mask)]
Out[34]:
array([ 89, 206, 206, 143, 152, 212,  14,  45, 122, 159, 235, 177, 188,
        67, 208, 229, 141, 215, 230, 230], dtype=uint8)
将圆周长处的图像值设置为0:

In [35]: img[np.nonzero(mask)] = 0

In [36]: img
Out[36]:
array([[ 88, 239, 212, 160,   0,  85, 249, 242,  88],
       [ 47, 230,   0,   0,  63,   0,   0,  67,  58],
       [162,   0,   0, 213, 208, 169, 228,   0, 229],
       [230,   0, 103, 201, 188, 231,  80,   0, 131],
       [  0,  31, 148, 158,  73, 215, 152, 158,   0],
       [213,   0, 148, 237,  92, 115, 152,   0, 223],
       [234,   0, 141, 173,  14,  18, 242,   0, 147],
       [ 53, 194,   0,   0,  37,   0,   0, 167,  82],
       [ 72,  78, 152,  76,   0, 128, 137,  25, 168]], dtype=uint8)
您也可以轻松获得坐标:

In [56]: np.where(mask)
Out[56]:
(array([0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8]),
 array([4, 2, 3, 5, 6, 1, 7, 1, 7, 0, 8, 1, 7, 1, 7, 2, 3, 5, 6, 4]))

OP要求的是圆边缘的周长像素,而不是以圆为中心的ROI。OP要求的是圆边缘的周长像素,而不是以圆为中心的ROI。这两个函数都可以很容易地矢量化。特别是第二个——只需将
math
函数替换为
numpy
函数,并为
d
使用数组即可。您可以直接使用x和y坐标对应的两对数组对图像进行索引(在舍入并显式转换为int之后)。@AlexanderReynolds true,我将在moment@api55谢谢,您的第二个解决方案非常有效。然而,即使围绕中心的点数小于360,它也会吐出360个点。例如,半径为1时,将生成360个点,而不是4或8个点。你知道如何确定角度步长吗?也就是说,如果半径为1,则步长为45或90。@api55可能以下是正确的?与范围(360)内的d的
相反:
范围(0,360,数学地板(360/(半径*4)))内的d将是
替换
4
范围内的
8
视情况而定。@JakeM问题是很多点都是相同的。。。您始终可以筛选重复项。但也许你可以做一些类似于除以半径*4的事情,但是给它加上一个遮罩,两个函数都可以很容易地矢量化。特别是第二个——只需将
math
函数替换为
numpy
函数,并为
d
使用数组即可。您可以直接使用x和y坐标对应的两对数组对图像进行索引(在舍入并显式转换为int之后)。@AlexanderReynolds true,我将在moment@api55谢谢,您的第二个解决方案非常有效。然而,即使围绕中心的点数小于360,它也会吐出360个点。例如,半径为1时,将生成360个点,而不是4或8个点。你认识何