我正在使用cv 2来计算所附面罩图像中存在的对象之间的线.对象的方向/形状可能与我数据集中的其他面罩图像不同(水平、垂直).但问题是,我用来计算直线的方法并不可靠. 它适用于少数图像,但未能为其他面罩图像准确地画出一条线.有人能提出替代方法吗?

this is the raw mask image

This is how a line shall be drawn (considering objects orientation)

这是代表我方法的代码.我将非常感谢您的任何帮助.

import numpy as np
import cv2
import matplotlib.pyplot as plt

image_bgr = cv2.imread(IMAGE_PATH)

mask = masks[1]


mask_uint8 = mask.astype(np.uint8) * 255


contours, _ = cv2.findContours(mask_uint8, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for c in contours:
    # Calculate the centroid (center point) of the contour
    M = cv2.moments(c)
    cx = int(M['m10'] / M['m00'])
    cy = int(M['m01'] / M['m00'])
    
    
    cv2.drawContours(image_bgr, [c], -1, (255, 0, 0), 3)
    cv2.circle(image_bgr, (cx, cy), 5, (0, 255, 0), -1)
    
    
    left_side_point = tuple(c[c[:, :, 0].argmin()][0])
    right_side_point = tuple(c[c[:, :, 0].argmax()][0])
    center_point = (cx, cy)
    
    
    left_center_point = ((left_side_point[0] + center_point[0]) // 2, (left_side_point[1] + center_point[1]) // 2)
    right_center_point = ((right_side_point[0] + center_point[0]) // 2, (right_side_point[1] + center_point[1]) // 2)
    
    cv2.line(image_bgr, left_side_point, left_center_point, (0, 0, 255), 2)
    cv2.line(image_bgr, left_center_point, center_point, (0, 0, 255), 2)
    cv2.line(image_bgr, center_point, right_center_point, (0, 0, 255), 2)
    cv2.line(image_bgr, right_center_point, right_side_point, (0, 0, 255), 2)


plt.imshow(image_bgr)
plt.show()
´´´

推荐答案

当我进行粒子扫描分析时,我最终采用了类似PCA的方法:

%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
import cv2
im = cv2.imread("mask.png", 0) # read as gray
y, x = np.where(im) # get non-zero elements
centroid = np.mean(x), np.mean(y) # get the centroid of the particle
x_diff = x - centroid[0] # center x
y_diff = y - centroid[1] # center y
cov_matrix = np.cov(x_diff, y_diff) # get the convariance
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) # apply EVD
indicesForSorting = np.argsort(eigenvalues)[::-1] # sort to get the primary first
eigenvalues = eigenvalues[indicesForSorting]
eigenvectors = eigenvectors[:, indicesForSorting]
plt.figure()
plt.imshow(im, cmap = "gray") # plot image
vecPrimary = eigenvectors[:, 0] * np.sqrt(eigenvalues[0])
plt.plot([centroid[0] - vecPrimary[0], centroid[0] + vecPrimary[0]], 
        [centroid[1] - vecPrimary[1], centroid[1] + vecPrimary[1]])
vecSecondary = eigenvectors[:, 1] * np.sqrt(eigenvalues[1])
plt.plot([centroid[0] - vecSecondary[0], centroid[0] + vecSecondary[0]], 
        [centroid[1] - vecSecondary[1], centroid[1] + vecSecondary[1]])

Results

我喜欢这种方法,因为它也扩大了界限.如果您不希望这样做,您可以获得这条线的Angular 并绘制无限Angular ,然后用图像将其遮盖.希望这对您有进一步帮助

编辑:用开放画线

### same analysis as before
im = cv2.imread("mask.png")
pt1 = (int(centroid[0] - vecPrimary[0]), int(centroid[1] - vecPrimary[1]))
pt2 = (int(centroid[0] + vecPrimary[0]), int(centroid[1] + vecPrimary[1]))
cv2.line(im, pt1, pt2, (255, 0, 0), 2)  # blue line
pt1 = (int(centroid[0] - vecSecondary[0]), int(centroid[1] - vecSecondary[1]))
pt2 = (int(centroid[0] + vecSecondary[0]), int(centroid[1] + vecSecondary[1]))
cv2.line(im, pt1, pt2, (0, 0, 255), 2)  # redline
cv2.imwrite("maskWithLines.png", im)

结果:

lined

编辑:正如我在回答中所说,只需将这些载体乘以一个比例,然后使用屏蔽为biwise_and:

im = cv2.imread("mask.png")
imGray = cv2.imread("mask.png", 0) # read imgray
y, x = np.where(imGray) # get non-zero elements
centroid = np.mean(x), np.mean(y) # get the centroid of the particle
x_diff = x - centroid[0] # center x
y_diff = y - centroid[1] # center y
cov_matrix = np.cov(x_diff, y_diff) # get the convariance
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) # apply EVD
indicesForSorting = np.argsort(eigenvalues)[::-1] # sort to get the primary first and secondary second
eigenvalues = eigenvalues[indicesForSorting] # sort eigenvalues
eigenvectors = eigenvectors[:, indicesForSorting] # sort eigenvectors
Scale = 100 # this can be adjusted, iut is actually not important as long as it is a very high value
vecPrimary = eigenvectors[:, 0] * np.sqrt(eigenvalues[0]) * Scale
vecSecondary = eigenvectors[:, 1] * np.sqrt(eigenvalues[1]) * Scale
pt1 = (int(centroid[0] - vecPrimary[0]), int(centroid[1] - vecPrimary[1]))
pt2 = (int(centroid[0] + vecPrimary[0]), int(centroid[1] + vecPrimary[1]))
cv2.line(im, pt1, pt2, (255, 0, 0), 2)  # blue line
pt1 = (int(centroid[0] - vecSecondary[0]), int(centroid[1] - vecSecondary[1]))
pt2 = (int(centroid[0] + vecSecondary[0]), int(centroid[1] + vecSecondary[1]))
cv2.line(im, pt1, pt2, (0, 0, 255), 2)  # red line
im = cv2.bitwise_and(im, im, mask = imGray) # mask the lines
cv2.imwrite("maskWithLines.png", im)

结果如下:

Extended lines

Python相关问答推荐

使用子字符串动态更新Python DataFrame中的列

Pandas数据帧处理Pandas表中Json内的嵌套列表以获取后续Numpy数组

如何使用scikit-learn Python库中的Agglomerative集群算法以及集群中声明的对象数量?

Polars -转换为PL后无法计算熵.列表

自定义新元未更新参数

将行从一个DF添加到另一个DF

在matplotlib动画gif中更改配色方案

如何使用entry.bind(FocusIn,self.Method_calling)用于使用网格/列表创建的收件箱

如何使用没有Selenium的Python在百思买着陆页面上处理国家/地区 Select ?

使用polars .滤镜进行切片速度比pandas .loc慢

仅从风格中获取 colored颜色 循环

Pandas 有条件轮班操作

Excel图表-使用openpyxl更改水平轴与Y轴相交的位置(Python)

通过pandas向每个非空单元格添加子字符串

修复mypy错误-赋值中的类型不兼容(表达式具有类型xxx,变量具有类型yyy)

当独立的网络调用不应该互相阻塞时,'

为什么np. exp(1000)给出溢出警告,而np. exp(—100000)没有给出下溢警告?

Matplotlib中的字体权重

以逻辑方式获取自己的pyproject.toml依赖项

在代码执行后关闭ChromeDriver窗口