如何在图片中找到这个化学试纸? OpenCV canny边缘检测不绘制边界框

问题描述 投票:0回答:3

我有一个图像,我想做边缘检测并为其绘制边界框,我的问题是我的Python代码没有绘制边界框,我不确定它是否是这样,因为它无法检测到其中的任何对象它或者我只是画错了矩形。

1

这是我的尝试

import cv2
import numpy as np

img = cv2.imread("image1.jpg")
(B, G, R) = cv2.split(img)
img = cv2.Canny(B, 20, 100)   # Blue channel gives the best box so far
# img = cv2.Canny(R, 20, 100)
# img = cv2.Canny(R, 20, 100)


ret,thresh = cv2.threshold(img,20,100,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)


cnt = contours[0]
M = cv2.moments(cnt)

for c in contours:
    rect = cv2.minAreaRect(c)
    box = cv2.boxPoints(rect)
    box = np.intp(box)
    img = cv2.drawContours(img,[box],0,(0,0,255),2)



# display the image with bounding rectangle drawn on it 
# cv2.namedWindow('Bounding Rectangle', cv2.WINDOW_KEEPRATIO)
cv2.imshow('Bounding Rectangle', img) 

cv2.waitKey(0) 
cv2.destroyAllWindows() 

这会产生这个图像

2

我期待这样的图像:

3

python opencv image-processing computer-vision object-detection
3个回答
4
投票

我的做法:

  • 校正白平衡,使背景失去色调
  • HSV,获取饱和通道、阈值
  • 轮廓,最小区域矩形

此方法可检测所有四个彩色方块。

# gray = im.mean(axis=(0,1), dtype=np.float32) # gray world
gray = np.median(im, axis=(0,1)).astype(np.float32) # majority vote
print(gray) # [137. 127. 140.]
balanced = (im / gray) * 0.8 # some moderate scaling so it's not "overexposed"

enter image description here

hsv = cv.cvtColor(balanced, cv.COLOR_BGR2HSV)
H,S,V = cv.split(hsv)
# squares nicely visible

enter image description here

为了比较,源的饱和通道,没有白平衡:

enter image description here

print(S.min(), S.max()) # 0.0 0.9125462
mask = (S >= 0.3)

mask

(contours, _) = cv.findContours(mask.astype(np.uint8), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
hull = cv.convexHull(np.concatenate(contours))
rrect = cv.minAreaRect(hull)
# visualization
canvas = im.copy()
cv.drawContours(image=canvas, contours=contours, contourIdx=-1, color=(255,255,0), thickness=7)
# cv.drawContours(image=canvas, contours=[hull], contourIdx=-1, color=(255,255,0), thickness=7)
rrect_points = cv.boxPoints(rrect).round().astype(int)
cv.polylines(canvas, [rrect_points], isClosed=True, color=(0,255,255), thickness=3)

result


1
投票

我对阈值进行了一些操作,并跳过了拆分通道以仅使用蓝色通道的步骤,并跳过使用

Canny
。尝试:

import cv2
import numpy as np
# Load the image
cimg = cv2.imread('bBox.jpg')
# Convert to grayscale
img = cv2.cvtColor(cimg, cv2.COLOR_BGR2GRAY)
# Apply threshold or other color segmentation
_, img = cv2.threshold(img, 95, 255, cv2.THRESH_BINARY)
# Find contours
contours , _ = cv2.findContours(img, 1, 2)
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

for cnt in contours :
    # Fit a minimum area rectangle
    rect = cv2.minAreaRect(cnt)
    box = cv2.boxPoints(rect)
    box = np.intp(box)
    # Draw the bounding box
    cv2.drawContours(cimg, [box], 0, (0, 255, 0), 5)

# Show the image
cv2.imshow('Bounding Boxes', cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()

在我在代码中使用的源图像和带有结果边界框的图像下方:

originalImage

bBoxes

如果您想要整体框,您可以重复使用找到的边界框坐标来提取您需要绘制所需框的这些坐标。

注意,OpenCV 对象检测适用于白色对象,因此为了获得更好的结果并消除整个图像上的边界框,请使用:

img=cv2.bitwise_not(img) 

在搜索轮廓之前反转图像。

下面的代码展示了原理如何绘制整体边界框(使用适当的更好的算法进行调整以覆盖更广泛的情况):

import cv2
import numpy as np
cimg = cv2.imread('bBox.jpg')
img = cv2.cvtColor(cimg, cv2.COLOR_BGR2GRAY)
_, img = cv2.threshold(img, 95, 255, cv2.THRESH_BINARY)
img=cv2.bitwise_not(img)
contours , _ = cv2.findContours(img, 1, 2)
bBoxes = []
for cnt in contours :
    rect = cv2.minAreaRect(cnt)
    box = cv2.boxPoints(rect)
    box = np.intp(box)
    bBoxes += [ list(xy) for xy in list(box) ]
bBoxes=sorted(bBoxes)
bBox=np.array( [ bBoxes[1] ] + [ bBoxes[0] ] + [ bBoxes[-10] ] + [ bBoxes[-1] ])
cv2.drawContours(cimg, [bBox], 0, (0, 255, 0), 5)
# Show the image
cv2.imshow('Rotated Bounding Box', cimg)
cv2.waitKey(0)

overallBoundingBox


0
投票

图像质量不是很好。 GaussianBlur 用于使边缘更加清晰并消除噪音

 import cv2
import numpy as np

img = cv2.imread("image1.jpg")

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (5,5), 0)

_, img_thresh = cv2.threshold(img_blur, 120, 255, cv2.THRESH_BINARY) # cv2.THRESH_BINARY + cv2.THRESH_OTSU can use

cv2.imshow("thresh", img_thresh)

contours,hierarchy = cv2.findContours(img_thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)


cnt = contours[0]
M = cv2.moments(cnt)

for c in contours:
    rect = cv2.minAreaRect(c)
    box = cv2.boxPoints(rect)
    box = np.intp(box)
    img = cv2.drawContours(img,[box],0,(0,0,255),2)

# # display the image with bounding rectangle drawn on it 
cv2.imshow('Bounding Rectangle', img) 

cv2.waitKey(0) 
cv2.destroyAllWindows() 

img_thresh

结果

© www.soinside.com 2019 - 2024. All rights reserved.