I am trying to extract small objects from this image. I have applied Watershed algorithm for segmentation. How do I separate objects based on their color? I am trying to follow this guide but I am getting stuck with an exception error.
Image that needs extraction:
Code screenshot:
There's no need for real color detection here, since processing is done on the output of cv2.watershed
. That's an "image" markers
of type np.int32
with values 0, 1, 2, 3, ...
for the single markers detected by cv2.watershed
, whereas 0
is the background. So, there's nothing more to do than iterating all marker values (let's say i
), mask the portion where markers == i
, and find the corresponding coordinates of the bounding rectangle, copy that part to a new image and save this to some file.
Here's some code, where the cv2.watershed
was mimicked by using cv2.findContours
and cv2.drawContours
accordingly ( the interesting part regarding the question is solely the second for
loop ):
import cv2
import numpy as np
from matplotlib import pyplot as plt
from skimage import io # Only needed for web grabbing images
# Load some image with circles from web
image = io.imread('https://www.teachertoolsinc.com/images/detailed/26/TCR77379.png')
plt.figure(1), plt.imshow(image), plt.title('original image'), plt.tight_layout()
# Mimic watershed result using findContours and drawContours
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
gray = cv2.threshold(gray, 16, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
markers = np.zeros_like(gray).astype(np.int32)
for i, cnt in enumerate(cnts):
markers = cv2.drawContours(markers, [cnt], -1, i+1, cv2.FILLED)
plt.figure(2), plt.imshow(markers), plt.title('markers'), plt.colorbar(), plt.tight_layout()
plt.show()
# Assuming we only have markers now; iterate all values and crop image part
for i in np.arange(1, np.max(markers[:, :])+1):
pixels = np.array(np.where(markers == i)).astype(np.int32)
x1 = np.min(pixels[1, :])
x2 = np.max(pixels[1, :])
y1 = np.min(pixels[0, :])
y2 = np.max(pixels[0, :])
cv2.imwrite(str(i) + '.png', image[y1:y2, x1:x2, :])
That's the input image:
That's the mimicked markers
"image" (cf. to provided image in question):
And, here are two of the cut circles:
Hope that helps!
-----------------------
System information
-----------------------
Python: 3.8.1
Matplotlib: 3.2.0rc1
NumPy: 1.18.1
OpenCV: 4.1.2
-----------------------
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.