OpenCV在不良图像上使用各种方法绘制轮廓

时间:2019-03-01 19:02:23

标签: python opencv image-processing

我目前正在一个项目中,通过图像处理来测量明渠中的水位。我的主要问题是由于实验室条件的限制,我必须处理有问题的图像。 (即照明不良,背景不良等)。current sample image

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

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

我的问题是;我是完全犯错了吗,还是我当前使用的图像根本不够好而无法处理?我应该尝试其他库或语言吗?这是我当前的代码;

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()

1 个答案:

答案 0 :(得分: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)

结果 enter image description here

我做了什么?: 我将在图片中为您解释。

  

灰度阈值

Threshold

  

模糊阈值以填充行

enter image description here

  

所有非纯白色[255,255,255]都变为[0,0,0]

enter image description here

  

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

enter image description here

  

绘制特定大小的轮廓-摆脱太大和太小的

enter image description here

  

最后使用cv2.polly清除国家/地区以外的所有内容,并将其变为黑色。请参阅第一张图片以获取结果

就水位测量而言,我并不十分了解,也不想深入研究,但是也许您可以使用sobely

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

enter image description here