Python:使用OpenCV提取形状内对象

hts6caw3  于 2022-11-15  发布在  Python
关注(0)|答案(2)|浏览(197)

我需要使用python OpenCV从这个矩形框中提取图像。

我看过并尝试过几种从形状内部提取内容的方法,但每种方法都有局限性。(0,255,0)或红色(255,0,0)。然而,我的问题是红框有一些透明/不透明,使矩形的识别困难得多。矩形的红色像素颜色范围从175- 220,但是图像的其余部分也具有类似的红色色调,使得提取更加困难。

我对OpenCV还是个新手,所以非常感谢您的帮助。我已经在this线程上尝试了这两种解决方案,但是都没有产生预期的结果。

pqwbnv8z

pqwbnv8z1#

以下是一个可能的解决方案:
1.图像转换为HSV
1.红色阈值用于分割矩形
1.应用一些形态学以尽可能闭合轮廓
1.检测外部轮廓
1.根据面积过滤噪声斑点;您正在寻找最大的轮廓
1.获取轮廓的边界矩形
1.切片使用边界矩形的图像
让我们看看代码:

  1. # imports:
  2. import cv2
  3. import numpy as np
  4. # image path
  5. path = "D://opencvImages//"
  6. fileName = "uHNzL.jpg"
  7. # Reading an image in default mode:
  8. inputImage = cv2.imread(path + fileName)
  9. # Deep copy for results:
  10. inputImageCopy = inputImage.copy()
  11. # Convert the image to the HSV color space:
  12. hsvImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2HSV)
  13. # Set the HSV values:
  14. lowRange = np.array([144, 105, 0])
  15. uppRange = np.array([179, 255, 255])
  16. # Create the HSV mask
  17. binaryMask = cv2.inRange(hsvImage, lowRange, uppRange)

这是面具:

正如你所看到的,矩形(大部分)在那里。让我们尝试用一些形态学来改善轮廓。一些扩张和侵 eclipse 应该可以做到这一点:

  1. # Apply Dilate + Erode:
  2. kernel = np.ones((3, 3), np.uint8)
  3. binaryMask = cv2.morphologyEx(binaryMask, cv2.MORPH_DILATE, kernel, iterations=3)
  4. binaryMask = cv2.morphologyEx(binaryMask, cv2.MORPH_ERODE, kernel, iterations=3)

这就是结果:

矩形稍大一些,但噪声也大一些。但是,我们要寻找最大的斑点,所以我们可以按面积过滤。让我们裁剪最大的斑点:

  1. # Find the target blobs on the binary mask:
  2. contours, hierarchy = cv2.findContours(binaryMask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  3. # Alright, just look for the outer bounding boxes:
  4. for _, c in enumerate(contours):
  5. # Get blob area:
  6. blobArea = cv2.contourArea(c)
  7. # Set minimum area:
  8. minArea = 1000
  9. if blobArea > minArea:
  10. # Get the bounding rectangle:
  11. boundRect = cv2.boundingRect(c)
  12. # Bondary offset:
  13. offset = 15
  14. # Draw the rectangle on the input image:
  15. # Get the dimensions of the bounding rect:
  16. rectX = int(boundRect[0] + offset)
  17. rectY = int(boundRect[1] + offset)
  18. rectWidth = int(boundRect[2] - 2 * offset)
  19. rectHeight = int(boundRect[3] - 2 * offset)
  20. # Green Color, detected blobs:
  21. color = (0, 255, 0)
  22. cv2.rectangle(inputImageCopy, (int(rectX), int(rectY)),
  23. (int(rectX + rectWidth), int(rectY + rectHeight)), color, 2)
  24. # Crop contour:
  25. croppedImage = inputImage[rectY:rectY + rectHeight, rectX:rectX + rectWidth]
  26. cv2.imshow("croppedImage", croppedImage)
  27. cv2.waitKey(0)
  28. cv2.imshow("Rectangles", inputImageCopy)
  29. cv2.waitKey(0)

现在,因为我们正在处理一个变形图像,矩形二进制轮廓比实际的红色矩形稍大,所以我引入了一个偏移量,以更紧密地裁剪图像。
这是偏移量为15像素的边框:

这是裁剪后的图像:

展开查看全部
4smxwvx5

4smxwvx52#

非常感谢你的帮助;这是非常有帮助的!我确实必须修改代码,以概括它足以适用于数百万张图像。我得到了大约95%+的准确率。错误包括图像中的多个建筑物非常接近红色屋顶,深红色土壤,车辆...基本上任何红色的东西。因此,我把最小面积的阈值提高到一个很高的值,以排除红色框外的大的红色物体。希望这对其他人有帮助。
主要变更...
1.我删除了偏移,它没有概括得足够好,在一些图像中,所需的内容被从最终产品中剪掉了。
1.我确实需要合并轮廓以避免出现大量较小的矩形,这也是我增加minArea阈值的原因。我发现即使是100的小减量有时也会产生2+轮廓,所以我必须在计算边界矩形之前将它们合并。
1.非常重要的是,我创建了一个上限和下限颜色范围,以确保我得到的是红色框所涵盖的整个区域。由于红色框的透明度,色调和饱和度无处不在,这有助于始终确保我捕捉到所需的内容。
希望这对其他人有帮助。

  1. # Original image
  2. src = cv2.imread(img_file, cv2.IMREAD_COLOR)
  3. img = cv2.cvtColor(src, cv2.COLOR_BGR2RGB )
  4. # HSV
  5. hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
  6. # lower boundary RED color range values; Hue (0 - 10)
  7. lower1 = np.array([0, 100, 20])
  8. upper1 = np.array([10, 255, 255])
  9. # upper boundary RED color range values; Hue (160 - 180)
  10. lower2 = np.array([160,100,20])
  11. upper2 = np.array([179,255,255])
  12. lower_mask = cv2.inRange(hsv, lower1, upper1)
  13. upper_mask = cv2.inRange(hsv, lower2, upper2)
  14. binaryMask = lower_mask + upper_mask
  15. # kernel dialation and erode
  16. kernel = np.ones((3, 3), np.uint8)
  17. binaryMask = cv2.morphologyEx(binaryMask, cv2.MORPH_DILATE, kernel, iterations=3)
  18. binaryMask = cv2.morphologyEx(binaryMask, cv2.MORPH_ERODE, kernel, iterations=3)
  19. # Find the target blob
  20. contours, hierarchy = cv2.findContours(binaryMask, cv2.RETR_EXTERNAL,
  21. cv2.CHAIN_APPROX_SIMPLE)
  22. flag = True
  23. minArea = 50_000
  24. while flag and minArea > 100:
  25. contours_ = [contour for contour in contours
  26. if cv2.contourArea(contour) > minArea]
  27. contoursAreas = [cv2.contourArea(contour) for contour in contours]
  28. if contours_:
  29. contour = np.vstack(contours_)
  30. flag = False
  31. else:
  32. minArea -= 500
  33. # blob to bounding rectangle
  34. offset = 15
  35. boundRect = cv2.boundingRect(contour)
  36. rectX = int(boundRect[0])
  37. rectY = int(boundRect[1])
  38. rectWidth = int(boundRect[2])
  39. rectHeight = int(boundRect[3])
  40. # Crop orignal image and save image
  41. croppedImage = src[rectY:rectY + rectHeight, rectX:rectX + rectWidth]
  42. imgFName = os.path.split(img_file)[-1]
  43. imgFPath = os.path.join(OUT_IMG_PATH, imgFName)
  44. cv2.imwrite(imgFPath, croppedImage)
展开查看全部

相关问题