当前位置: 代码迷 >> python >> Python和OpenCV图像目标检测和区分
  详细解决方案

Python和OpenCV图像目标检测和区分

热度:135   发布时间:2023-06-13 13:37:41.0

我的任务是为我的火箭俱乐部编写一个程序,以检测和区分海拔上的三个“目标”。 这些目标是我拥有RGB值的3个大型防水布。

当我开始这个项目时,我使用防水布的精确RGB值在GoogleEarth图像上覆盖了3个矩形,并且我的代码可以完美地工作。 但是,当我实际收到防水布并开始在地面上拍照时,我的代码无法识别具有我指定的RGB颜色边界的防水布。

我试图将图像转换为HSV色彩空间,但是我无法使其正常工作。 我还考虑过使用轮廓-试图让程序识别出限制每个目标的4条直线。 问题是这些图像将在户外拍摄,因此我无法控制周围的光照条件。

是否有人对哪种色彩空间或计算机视觉方法可以识别和区分这些目标(与室外照明无关)有任何想法?

处理后的原始图像
有待确定的实际油布

这是代码:

import cv2
import numpy as np

image = cv2.imread('2000 ft.png', 1)
#hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)


#cv2.waitKey(0)
cv2.destroyAllWindows()

# define target strings
targ = ['Target 1 - Blue', 'Target 2 - Yellow', 'Target 3 - Red']
i = 0

# BGR boundaries of colors
boundaries = [
# 0, 32, 91
    ([40, 10, 0], [160, 60, 20]),
# 255, 209, 0
    ([0, 180, 220], [20, 230, 255]),
# 166, 9, 61
    ([40, 0, 150], [80, 30, 185]),
]

# colors for rectangle outlines 
colors = [
          ([91, 32, 0]), ([0, 209, 255]), ([61, 9, 166])
]

# # loop over the boundaries
for (lower, upper) in boundaries:

     # create NumPy arrays from the boundaries
    lower = np.array(lower, dtype = "uint16")
    upper = np.array(upper, dtype = "uint16")

     # find the colors within the specified boundaries and apply
     # the mask
    mask = cv2.inRange(image, lower, upper)
    output = cv2.bitwise_and(image, image, mask = mask)
    # frame threshold
    frame_threshed = cv2.inRange(image, lower, upper)
    imgray = frame_threshed

    # iteratively view masks 
    cv2.imshow('imgray',imgray)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    ret,thresh = cv2.threshold(frame_threshed,127,255,0)
    contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

     # Find the index of the largest contour
    areas = [cv2.contourArea(c) for c in contours]
    max_index = np.argmax(areas)
    cont=contours[max_index]

    # putting text and outline rectangles on image
    x,y,w,h = cv2.boundingRect(cont)
    cv2.rectangle(image,(x,y),(x+w,y+h),colors[i],2)
    cv2.putText(image, targ[i], (x-50, y-10), cv2.FONT_HERSHEY_PLAIN, 0.85, (0, 255, 0))
     # cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),4)
    cv2.imshow("Show",image)
    cv2.waitKey()
    cv2.destroyAllWindows()
    i += 1

cv2.destroyAllWindows()

我使用我没有很多经验的OpenCV库,用我有很多经验的Python编写了这段代码。非常感谢您的帮助!

相机(实际上是火箭)的颜色将取决于环境光,并且不太可能是

# colors for rectangle outlines 
colors = [
          ([91, 32, 0]), ([0, 209, 255]), ([61, 9, 166])
]

您可以通过计算图像的像素坐标来进行检查,并进行打印。

如果您仍然可以更改标记,则我将使用对比度更高的标记,而不是使用单色(例如带有白色边框的蓝色正方形等),这样可以方便canny> findContour,以及随后的polypoly查找正方形。

如果不能更改标记,那么最好的选择是分离R,G和B通道,然后执行canny> findcontour。 我怀疑红色和蓝色方块会很好,但是黄色方块会变差,因为它融入了景观。

我已将代码移至python3 / OpenCV3,否则它基于您的代码

@pandamakes的主张正确。 您需要寻找与目标值接近的像素,但是不能假设会得到与该值非常接近的像素。

我添加了一个忽略边界的遮罩(周围有许多伪像),并修改了目标值,因为在现实生活中,您不太可能获得零值的像素(尤其是在有大气反射的航空图像中)

基本上,我正在寻找一个值接近目标值的区域,并使用洪水填充来定位实际目标边界

编辑从RGB颜色空间移至CIELab并仅使用Ab彩色通道来增强照明条件的鲁棒性

import cv2
import numpy as np

image = cv2.imread('tarpsB.jpg', 1)
#convert to CIELab
cielab = cv2.cvtColor(image, cv2.COLOR_BGR2Lab)

# define target strings
targ = ['Target 1 - Blue', 'Target 2 - Yellow', 'Target 3 - Red']
i = 0

# colors = [
#           ([91, 40, 40]), ([40, 209, 255]), ([81, 60, 166])
# ]
# rough conversion of BGR target values to CIELab 
cielab_colors = [
          ([20, 20, -40]), ([80, 0, 90]), ([40, 70, 30])
]

# # loop over the boundaries
height = image.shape[0]
width = image.shape[1]
mask = np.ones(image.shape[0:2])

cv2.circle( mask, (int(width/2), int(height/2)), int(height/2), 0, -1 );
mask = 1-mask
mask = mask.astype('uint8')

#for color in colors:
for cielab_color in cielab_colors:
    diff_img = cielab.astype(float)
    # find the colors within the specified boundaries and apply
    # the mask

    diff_img[:, :, 0] = np.absolute( diff_img[:, :, 0] - 255 * cielab_color[0] / 100 )
    diff_img[:, :, 1] = np.absolute( diff_img[:, :, 1] - (cielab_color[1] + 128) )
    diff_img[:, :, 2] = np.absolute( diff_img[:, :, 2] - (cielab_color[2] + 128) )


    diff_img = ( diff_img[:, :, 1] + diff_img[:, :, 2]) / 2
    diff_img = cv2.GaussianBlur(diff_img, (19, 19), 0)
    minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(diff_img, mask)
    min_img = np.array(diff_img/255)

    ff_mask = np.zeros( (height + 2, width + 2), np.uint8)
    cv2.floodFill(image, ff_mask, minLoc, 255, (12, 12, 12), (12, 12, 12), cv2.FLOODFILL_MASK_ONLY );
    ff_mask = ff_mask[1:-1, 1:-1]
    im2, contours, hierarchy = cv2.findContours(ff_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    # Find the index of the largest contour
    areas = [cv2.contourArea(c) for c in contours]
    max_index = np.argmax(areas)
    cont=contours[max_index]
    print('target color = {}'.format(image[minLoc[1], minLoc[0], :]))
    # putting text and outline rectangles on image
    x,y,w,h = cv2.boundingRect(cont)
    cv2.rectangle(image,(x,y),(x+w,y+h),colors[i],2)
    cv2.putText(image, targ[i], (x-50, y-10), cv2.FONT_HERSHEY_PLAIN, 0.85, (0, 255, 0))

    cv2.imshow('diff1D',diff_img/255)
    cv2.imshow('ff_mask',ff_mask*255)
    cv2.waitKey(0)
    i += 1

cv2.imshow("Show",image)
cv2.waitKey(0)

cv2.destroyAllWindows()

编辑添加输出图像