【问题标题】:OpenCV drawing contours with various methods on a poor imageOpenCV 用各种方法在较差的图像上绘制轮廓
【发布时间】:2019-07-23 20:22:51
【问题描述】:

我目前正在开展一个项目,通过图像处理来测量明渠中的水位。我的主要问题是,由于我们的实验室条件,我必须处理相当有问题的图像。 (即光线不好,背景不好等)

目前这是我拥有的最好的图像,未来我会得到更好的,但现在这是我正在使用的。

由于图片中发生了很多事情,我决定过滤蓝色来绘制一些轮廓并选择我需要处理的那些。但我似乎无法很好地绕过它来检测每个蓝色矩形。我还尝试对图像进行灰度化,然后绘制轮廓,这似乎效果更好,但仍然不够。对于测量,我计划使用霍夫变换。

我的问题是;我是在完全错误地处理这个问题,还是我目前正在使用的图像根本不足以处理?我应该尝试不同的库或语言吗?这是我当前的代码;

from imutils import perspective
from imutils import contours
import numpy as np
import imutils
import cv2 as cv


blueLow = np.array([90, 50, 20])
blueHigh = np.array([130, 255, 255])

img = cv.imread("10ltsn.png")
imgHSV = cv.cvtColor(img, cv.COLOR_BGR2HSV)
mask = cv.inRange(imgHSV, blueLow, blueHigh)
##imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

##kernelOpen = np.ones((5,5))
##kernelClose = np.ones((20,20))
##maskOpen = cv.morphologyEx(mask, cv.MORPH_OPEN, kernelOpen)
##maskClose = cv.morphologyEx(maskOpen, cv.MORPH_CLOSE, kernelClose)

##imgray = cv.GaussianBlur(imgray, (5,5), 0)
##imgray = cv.bilateralFilter(imgray,9,75,75)

edge = cv.Canny(mask, 50, 200)
edge = cv.dilate(edge, None, iterations=1)
edge = cv.erode(edge, None, iterations=1)


cnt = cv.findContours(edge.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cnt = imutils.grab_contours(cnt)

##(cnt, _) = contours.sort_contours(cnt)

for k in cnt:
    if cv.contourArea(k) < 1000:
        continue

    main = img.copy()
    box = cv.minAreaRect(k)
    box = cv.boxPoints(box)
    box = np.array(box, dtype="int")

    box = perspective.order_points(box)
    cv.drawContours(main, [box.astype("int")], -1, (0, 255, 0), 1)

    for (x, y) in box:
        cv.circle(main, (int(x), int(y)), 5, (0, 0, 255), -1)

    cv.imshow("main", main)
    cv.waitKey(0)



##cv.imshow("img", img)
##cv.imshow("mask", mask)
##cv.imshow("mask2", mask2)
##cv.imshow("edge", edged)
##cv.imshow("maskClose", maskClose)
##cv.imshow("maskOpen", maskOpen)

##cv.waitKey(0)
cv.destroyAllWindows()

【问题讨论】:

  • 你能显示预期的结果吗?
  • 我希望能够找到屏幕截图中显示的每个矩形,这样我就可以分别在它们中工作以测量水深。 example

标签: python opencv image-processing


【解决方案1】:

不要太复杂。我使用了你的一些代码。

PS:我只能帮助你直到你可以专注于尝试测量水位。但最后我会给你一个提示

import numpy as np
import cv2

def show(img):
    cv2.imshow('a',img)
    cv2.waitKey()
    cv2.destroyAllWindows()


mask = cv2.imread("azC2r.jpg",0)
img = cv2.imread("azC2r.jpg")
print('Image shape: {}'.format(img.shape))

ret,thresh = cv2.threshold(mask,50,255,cv2.THRESH_BINARY)

thresh = cv2.blur(thresh,(7,7))
thresh[thresh<254]=0


kernel = np.ones((7,7))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
kernel = np.ones((9,9))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)


im2, contours,_ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

contours = [cnt for cnt in contours if cv2.contourArea(cnt)<100000]

cv2.drawContours(img, contours, -1, (0,255,0), 3)

# Thank to this snippet to
# https://stackoverflow.com/questions/37912928/fill-the-outside-of-contours-opencv
stencil = np.zeros(img.shape).astype(img.dtype)
color = [255, 255, 255]
cv2.fillPoly(stencil, contours, color)
img = cv2.bitwise_and(img, stencil)
# END of snippet
img[np.where(np.all(img==[255,255,255],axis = 2))]=[0,0,0]


show(img)

结果

我做了什么?: 我会用图片解释给你。

灰度阈值

模糊阈值以填充填充的线条

所有不是纯白色的 [255,255,255] 变成 [0,0,0]

用形态学技巧摆脱单独的小粒子

绘制特定尺寸的轮廓 - 去掉太大和太小的轮廓

最后用 cv2.polly 摆脱 countours 之外的所有内容并将其变为黑色。查看结果的第一张图片

至于水位测量我真的不知道也不想深入研究,但也许你可以玩sobely

sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)

【讨论】:

  • 哦,哇,这实际上更好更简单,谢谢。一旦我得到一些没有反射的图像,我会冷静地研究。
猜你喜欢
  • 2019-02-12
  • 2014-03-20
  • 2012-11-06
  • 1970-01-01
  • 2021-09-07
  • 2017-11-06
  • 2023-03-09
  • 1970-01-01
  • 2021-01-17
相关资源
最近更新 更多