0

I'm trying to identify whether the gray rectangle in the image shown below contains black stain.

Stain Image:

Stain Image

Stain Highlighted:

Stain Highlighted

import numpy 
import matplotlib.pyplot as plt
import cv2

path = r'F:\stain.tif'
img = cv2.imread(path)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_bin = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                   cv2.THRESH_BINARY_INV, 131, 15)

plt.imshow(img_bin, cmap='gray')
plt.show()

Using the OpenCV code above, I was able to create a picture that only whitens the black spot I want to locate as shown below.

Binary image:

binary image

However, I'm not sure how to move any further. My final goal is sorting out pictures that only have those black stains on gray rectangles from thousands of images.

Below is an example of a clean, gray rectangle image that should not be sorted.

Clean Rectangle:

Clean Rectangle

I saw on google using 'stats' array of cv2.connectedComponentsWithStats function might help.

Any advice will be deeply appreciated!

Michael S.
  • 3,050
  • 4
  • 19
  • 34
Hang Kim
  • 1
  • 1
  • That spot is not white. It is black. You title is not very accurate! – fmw42 Sep 03 '21 at 00:49
  • First, you can use template matching to locate. Then get the location region image to subtract your clear image. – yanzzz Sep 03 '21 at 01:09
  • 1
    Does the size or position of the gray rectangle in the image change? Are the lighting and camera exposure identical across all your images? What is the maximum size of the black stain in terms of percentage of the size of the gray rectangle - I mean could the black stain cover 90% of the gray rectangle? – Mark Setchell Sep 03 '21 at 08:03
  • @Mark Sethchell Yes, I should've put this in the question. The position of rectangle will be similar throughout but won't be exactly the same. The black stain can be large as 1/5 size of the rectangle. The lighting and the background will be also similar throughout the pictures, but again, won't have exactly the same rgb. – Hang Kim Sep 03 '21 at 13:59

2 Answers2

1

Step 0: find the octagon, so you know what's inside and what's outside, and the edges of the octagon don't bother you.

Step 1: deal with the uneven illumination. Calculate a median of some kernel size (that's clearly larger than any defects/debris), then subtract that (or divide... but that's more advanced).

Step 2: threshold the "flat illumination" picture and find contours (cv.findContours). Filter by size (cv.contourArea), if necessary.

enter image description here

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
  • Thanks for the reply! Could you elaborate a bit more on your second point? I don't quite understand what is means nor the appoach. – Hang Kim Sep 05 '21 at 23:44
  • Also, could you guide me on how you made the shades on exclusively part outside the octagon? I was able to find the contour but was not sure how to make everything black (or possibly white) everything outside the contour. – Hang Kim Sep 06 '21 at 00:04
  • it's all just median filters, per-pixel arithmetic (subtracting whole arrays from each other and adding constants), and thresholding, and maybe some masking operations. I didn't need to find any contours because I don't need contours to produce this picture. – Christoph Rackwitz Sep 06 '21 at 07:51
0
grayImg[np.where(grayImg > 20)] = 255
cnts, _ = cv2.findContours(~grayImg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in cnts:
    x, y, w, h = cv2.boundingRect(c)
    cv2.circle(grayImg, (x+w//2, y+h//2), max(w, h), 127, 5)
print("Found any: ", len(cnts) > 0)
Shamshirsaz.Navid
  • 2,224
  • 3
  • 22
  • 36