jooloo jooloo - 2 months ago 25
Python Question

Batch processing and breaking up an image

I'm trying to segment each charm item in this collective image.

The shapes are irregular and inconsistent:

https://i.imgur.com/sf8nOau.jpg

I have another image where there is some consistency with the top row of items, but ideally I'd be able to process and brake up all items in one go:

http://i.imgur.com/WiiYBay.jpg

I have no experience with opencv so I'm just looking for best possible tool or approach to take. I've read about background subtraction as well as color clustering, but I'm not sure about those either.

Any ideas on how to best approach this? Thanks.

Answer

Code

import cv2
import numpy as np 

im=cv2.imread('so1.jpg')
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

kernel = np.ones((3,3),np.uint8)
res = cv2.dilate(thresh,kernel,iterations = 1)
res = cv2.erode(res,kernel,iterations = 1)
res = cv2.dilate(res,kernel,iterations = 1)

cv2.imshow('thresh',res)
_,contours, hierarchy = cv2.findContours(res.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
    x,y,w,h = cv2.boundingRect(cnt)
    cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)

cv2.imshow('image',im)
cv2.waitKey(0)
cv2.destroyAllWindows()

Output

enter image description here

Now having the contours you can crop them out

Code Update

import cv2
import numpy as np 

im=cv2.imread('so.jpg')
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

kernel = np.ones((3,3),np.uint8)
res = cv2.dilate(thresh,kernel,iterations = 1)
res = cv2.erode(res,kernel,iterations = 1)
res = cv2.dilate(res,kernel,iterations = 8)

cv2.imshow('thresh',res)
_,contours, hierarchy = cv2.findContours(res.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
count=0

for cnt in contours:
    blank=np.zeros(im.shape,dtype=np.uint8)
    x,y,w,h = cv2.boundingRect(cnt)
    epsilon = 0.001*cv2.arcLength(cnt,True)
    approx = cv2.approxPolyDP(cnt,epsilon,True)
    cv2.fillConvexPoly(blank,approx,(255, 255, 255))
    masked_image = cv2.bitwise_and(im, blank)
    cv2.imwrite('results_so/im'+str(count)+'.jpg',masked_image[y:y+h,x:x+w])
    count+=1
cv2.imshow('image',im)
cv2.waitKey(0)
cv2.destroyAllWindows()

results

good one

enter image description here

bad one

enter image description here

Some small noises are also detected as objects you can eliminate those by only taking contours whose area is greater than a certain value .

Comments