9 python opencv image-processing computer-vision
我从官方文档中学习了本教程.我运行他们的代码:
import numpy as np
import cv2
im = cv2.imread('test.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (0,255,0), 3)
Run Code Online (Sandbox Code Playgroud)
没关系:没有错误,但没有显示任何内容.我想显示他们在图片上显示的结果:
如何显示这样的计数结果(只是左边的结果或右边的结果)?我知道我必须使用cv2.imshow(something)
但在这种具体情况下如何使用?
ray*_*ica 15
首先,该示例仅向您展示如何使用简单近似绘制轮廓.请记住,即使您使用简单近似绘制轮廓,也会将其视为具有完全围绕矩形绘制的蓝色轮廓,如左图所示.只需将轮廓绘制到图像上,您将无法获得正确的图像.此外,您想比较两组轮廓 - 右侧的简化版本及左侧的完整表示.具体来说,您需要替换cv2.CHAIN_APPROX_SIMPLE
标志cv2.CHAIN_APPROX_NONE
以获得完整的表示.有关findContours
更多详细信息,请查看OpenCV文档:http: //docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#findcontours
此外,即使您将轮廓绘制到图像上,它也不会显示结果.你需要打电话cv2.imshow
给那个.但是,绘制轮廓本身并不会显示完整版和简化版之间的区别.教程提到您需要在每个轮廓点绘制圆圈,因此我们不应该使用cv2.drawContours
此任务.你应该做的是提取轮廓点并在每个点绘制圆圈.
因此,创建两个图像,如下所示:
# Your code
import numpy as np
import cv2
im = cv2.imread('test.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
## Step #1 - Detect contours using both methods on the same image
contours1, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
contours2, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
### Step #2 - Reshape to 2D matrices
contours1 = contours1[0].reshape(-1,2)
contours2 = contours2[0].reshape(-1,2)
### Step #3 - Draw the points as individual circles in the image
img1 = im.copy()
img2 = im.copy()
for (x, y) in contours1:
cv2.circle(img1, (x, y), 1, (255, 0, 0), 3)
for (x, y) in contours2:
cv2.circle(img2, (x, y), 1, (255, 0, 0), 3)
Run Code Online (Sandbox Code Playgroud)
请注意,上面的代码适用于OpenCV 2.对于OpenCV 3,还有一个额外的输出,cv2.findContours
这是您在这种情况下可以忽略的第一个输出:
_, contours1, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
_, contours2, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
Run Code Online (Sandbox Code Playgroud)
现在让我们慢慢地浏览代码.代码的第一部分就是您提供的内容.现在我们进入新的领域.
使用阈值图像,我们使用完整和简单近似检测轮廓.这将存储在两个列表中,contours1
并且contours2
.
轮廓本身存储为NumPy数组列表.对于提供的简单图像,应该只检测到一个轮廓,因此提取出列表的第一个元素,然后使用numpy.reshape
将3D矩阵重塑为其每行为(x, y)
点的2D形式.
下一步是(x, y)
从每组轮廓中取出每个点并在图像上绘制它们.我们以彩色形式制作原始图像的两个副本,然后我们使用cv2.circle
并迭代(x, y)
两组轮廓的每对点并填充两个不同的图像 - 每组轮廓一个.
现在,要获得上面看到的数字,有两种方法可以做到这一点:
matplotlib
,结合使用subplot
,imshow
以便您可以在一个窗口中显示两个图像.我将告诉你如何使用这两种方法来做到这一点:
只需将两个图像并排堆叠,然后显示图像:
out = np.hstack([img1, img2])
# Now show the image
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)
我将它们水平堆叠,以便它们是一个组合图像,然后用它来显示cv2.imshow
.
你可以使用matplotlib
:
import matplotlib.pyplot as plt
# Spawn a new figure
plt.figure()
# Show the first image on the left column
plt.subplot(1,2,1)
plt.imshow(img1[:,:,::-1])
# Turn off axis numbering
plt.axis('off')
# Show the second image on the right column
plt.subplot(1,2,2)
plt.imshow(img2[:,:,::-1])
# Turn off the axis numbering
plt.axis('off')
# Show the figure
plt.show()
Run Code Online (Sandbox Code Playgroud)
这应该在整个图形窗口内的单独子图中显示两个图像.如果你看一下我在imshow
这里打电话的方式,你会发现我正在交换RGB通道,因为OpenCV以BGR格式读取图像.如果要显示图像matplotlib
,则需要反转通道,因为图像是RGB格式(应该是这样).
要在注释中解决您的问题,您可以采用所需的轮廓结构(contours1
或contours2
)并搜索轮廓点. contours
是所有可能轮廓的列表,并且在每个轮廓内是以矩阵形状成形的3D矩阵N x 1 x 2
. N
将是表示轮廓的点的总数.我将删除单例第二维,以便我们可以将其作为N x 2
矩阵.另外,让我们现在使用轮廓的完整表示:
points = contours1[0].reshape(-1,2)
Run Code Online (Sandbox Code Playgroud)
我将假设您的图像只有一个对象,因此我索引为contours1
索引0.我解开矩阵使其成为单行向量,然后重新整形矩阵使其成为N x 2
.接下来,我们可以通过以下方式找到最小点:
min_x = np.argmin(points[:,0])
min_point = points[min_x,:]
Run Code Online (Sandbox Code Playgroud)
np.argmin
找到您提供的数组中最小值的位置.在这种情况下,我们希望沿着x
坐标或列进行操作.一旦找到这个位置,我们只需索引到我们的2D轮廓点阵列并提取出轮廓点.
您应该在代码末尾添加 cv2.imshow("Title", img) 。它应该是这样的:
import numpy as np
import cv2
im = cv2.imread('test.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(im, contours, -1, (0,255,0), 3)
cv2.imshow("title", im)
cv2.waitKey()
Run Code Online (Sandbox Code Playgroud)