用cv2.HoughCircles很难检测外圆 [英] Difficulty in detecting the outer circle with cv2.HoughCircles

查看:138
本文介绍了用cv2.HoughCircles很难检测外圆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正尝试在下图中检测圆形对象的外边界:

I am trying to detect the outer boundary of the circular object in the images below:

我尝试了OpenCV的Hough Circle,但是代码不适用于每个图像.我还尝试在Hough Circle中调整诸如minRadiusmaxRadius之类的参数,但不适用于所有图像.

I tried OpenCV's Hough Circle, but the code is not working for every image. I also tried to adjust parameters such as minRadius and maxRadius in Hough Circle but its not working on every image.

目的是从图像中检测出对象并对其进行裁剪.

预期输出:

源代码:

import imutils
import cv2
import numpy as np
from matplotlib import pyplot as plt


image = cv2.imread("path to the image i have provided")
r = 600.0 / image.shape[1]
dim = (600, int(image.shape[0] * r))
resized = cv2.resize(image, dim, interpolation = cv2.INTER_AREA)
cv2.imwrite("path to were we want to save downscaled image", resized)


image = cv2.imread('path of downscaled image')
image1 = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image2 = cv2.GaussianBlur(image1, (5, 5), 0)
edged = cv2.Canny(image2, 30, 150)

img = cv2.medianBlur(image2,5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)

circles = cv2.HoughCircles(edged,cv2.HOUGH_GRADIENT,1,20,
                            param1=50,param2=30,minRadius=200,maxRadius=280)

circles = np.uint16(np.around(circles))

max_circle = max(circles[0,:], key=lambda x:x[2])
# print(max_circle)

# # Create mask
height,width = image1.shape
mask = np.zeros((height,width), np.uint8)


for i in [max_circle]:
    cv2.circle(mask,(i[0],i[1]),i[2],(255,255,255),thickness=-1)  


masked_data = cv2.bitwise_and(image, image, mask=mask)

_,thresh = cv2.threshold(mask,1,255,cv2.THRESH_BINARY)

# Find Contour
contours = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[0]
x,y,w,h = cv2.boundingRect(contours[0])

# Crop masked_data
crop = masked_data[y:y+h,x:x+w]

#Code to close Window
cv2.imshow('OG',image)
cv2.imshow('Cropped ROI',crop)
cv2.imwrite("path to save roi image", crop)
cv2.waitKey(0)
cv2.destroyAllWindows()

推荐答案

第二个答案:一种基于颜色分割的方法.

Second Answer: an approach based on color segmentation.

虽然我正在编辑问题以提高其可读性,并且正在从共享链接中插入所有图像并调整其大小,以使每个人都可以更轻松地看到您要执行的操作,但我发现这个问题可能是基于按颜色细分

While I was editing the question to improve it's readability and was inserting and resizing all the images from the link you shared to make it easier for everyone to visualize what you are trying to do, it occurred to me that this problem might be a better candidate for an approach based on segmentation by color:

这种更简单(但更巧妙)的方法是假定卷轴几乎每次都出现在相同位置,并且每次都具有或多或少相同的尺寸:

This simpler (but clever) approach assumes that the reel appears pretty much in the same location and has more or less the same dimensions every time:

  • 要发现图像中卷轴的近似颜色,请定义感兴趣区域(ROI)的列表,以从中采样像素并确定 min max 颜色HSV颜色空间中该区域的大小. ROI的位置和大小是从图像大小得出的值.在下面的图片中,您可以看到ROI为带蓝色矩形的矩形:
  • To discover the approximate color of the reel in the image, define a list of Regions of Interest (ROIs) to sample pixels from and determine the min and max color of that area in the HSV color space. The location and size of the ROI are values derived from the size of the image. In the images below, you can see the ROIs as draw as blue-ish rectangles:

  • 一旦找到 min max HSV颜色,就可以使用cv2.inRange()进行阈值运算以分割卷轴:
  • Once the min and max HSV colors have been found, a threshold operation with cv2.inRange() can be executed to segment the reel:

  • 然后,遍历二进制图像中的所有轮廓,并假定最大的轮廓代表卷轴.使用此轮廓并将其绘制在单独的蒙版中,以便能够从原始图像中提取像素:

  • 在此阶段,还可以计算轮廓的边界框并提取其精确位置,以便稍后可以执行裁剪操作并完全隔离图像中的卷轴:

这种方法适用于在问题上共享的每张图片.

This approach works for EVERY image shared on the question.

源代码:

import cv2
import numpy as np
import sys


# initialize global H, S, V values
min_global_h = 179
min_global_s = 255
min_global_v = 255

max_global_h = 0
max_global_s = 0
max_global_v = 0

# load input image from the cmd-line
filename = sys.argv[1]
img = cv2.imread(sys.argv[1])
if (img is None):
    print('!!! Failed imread')
    sys.exit(-1)

# create an auxiliary image for debugging purposes
dbg_img = img.copy()

# initiailize a list of Regions of Interest that need to be scanned to identify good HSV values to threhsold by color
w = img.shape[1]
h = img.shape[0]
roi_w = int(w * 0.10)
roi_h = int(h * 0.10)
roi_list = []
roi_list.append( (int(w*0.25), int(h*0.15), roi_w, roi_h) )
roi_list.append( (int(w*0.25), int(h*0.60), roi_w, roi_h) )

# convert image to HSV color space
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# iterate through the ROIs to determine the min/max HSV color of the reel
for rect in roi_list:
    x, y, w, h = rect
    x2 = x + w
    y2 = y + h
    print('ROI rect=', rect)

    cropped_hsv_img = hsv_img[y:y+h, x:x+w]

    h, s, v = cv2.split(cropped_hsv_img)
    min_h  = np.min(h)
    min_s  = np.min(s)
    min_v  = np.min(v)

    if (min_h < min_global_h):
        min_global_h = min_h

    if (min_s < min_global_s):
        min_global_s = min_s

    if (min_v < min_global_v):
        min_global_v = min_v

    max_h  = np.max(h)
    max_s  = np.max(s)
    max_v  = np.max(v)

    if (max_h > max_global_h):
        max_global_h = max_h

    if (max_s > max_global_s):
        max_global_s = max_s

    if (max_v > max_global_v):
        max_global_v = max_v

    # debug: draw ROI in original image
    cv2.rectangle(dbg_img, (x, y), (x2, y2), (255,165,0), 4) # red


cv2.imshow('ROIs', cv2.resize(dbg_img, dsize=(0, 0), fx=0.5, fy=0.5))
#cv2.waitKey(0)
cv2.imwrite(filename[:-4] + '_rois.png', dbg_img)

# define min/max color for threshold
low_hsv = np.array([min_h, min_s, min_v])
max_hsv = np.array([max_h, max_s, max_v])
#print('low_hsv=', low_hsv)
#print('max_hsv=', max_hsv)

# threshold image by color
img_bin = cv2.inRange(hsv_img, low_hsv, max_hsv)
cv2.imshow('binary', cv2.resize(img_bin, dsize=(0, 0), fx=0.5, fy=0.5))
cv2.imwrite(filename[:-4] + '_binary.png', img_bin)

#cv2.imshow('img_bin', cv2.resize(img_bin, dsize=(0, 0), fx=0.5, fy=0.5))
#cv2.waitKey(0)

# create a mask to store the contour of the reel (hopefully)
mask = np.zeros((img_bin.shape[0], img_bin.shape[1]), np.uint8)
crop_x, crop_y, crop_w, crop_h = (0, 0, 0, 0)

# iterate throw all the contours in the binary image:
#   assume that the first contour with an area larger than 100k belongs to the reel
contours, hierarchy = cv2.findContours(img_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for contourIdx, cnt in enumerate(contours):
    area = cv2.contourArea(contours[contourIdx])
    print('contourIdx=', contourIdx, 'area=', area)

    # draw potential reel blob on the mask (in white)
    if (area > 100000):
        crop_x, crop_y, crop_w, crop_h = cv2.boundingRect(cnt)
        centers, radius = cv2.minEnclosingCircle(cnt)

        cv2.circle(mask, (int(centers[0]), int(centers[1])), int(radius), (255), -1) # fill with white
        break

cv2.imshow('mask', cv2.resize(mask, dsize=(0, 0), fx=0.5, fy=0.5))
cv2.imwrite(filename[:-4] + '_mask.png', mask)

# copy just the reel area into its own image
reel_img = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow('reel_img', cv2.resize(reel_img, dsize=(0, 0), fx=0.5, fy=0.5))
cv2.imwrite(filename[:-4] + '_reel.png', reel_img)

# crop the reel to a smaller image
if (crop_w != 0 and crop_h != 0):
    cropped_reel_img = reel_img[crop_y:crop_y+crop_h, crop_x:crop_x+crop_w]
    cv2.imshow('cropped_reel_img', cv2.resize(cropped_reel_img, dsize=(0, 0), fx=0.5, fy=0.5))

    output_filename = filename[:-4] + '_crop.png'
    cv2.imwrite(output_filename, cropped_reel_img)

cv2.waitKey(0)

这篇关于用cv2.HoughCircles很难检测外圆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆