0

I am trying to detect some spots from the image and save it in multiple images after cropping.

Image:

enter image description here

I just want to crop wbc.

Script: I am trying but not getting the idea.

import cv2
import numpy as np;

# Read image
im = cv2.imread("C:/Users/Desktop/MedPrime_Tech_Work/tag-145218-Default-10X.jpg", cv2.IMREAD_GRAYSCALE)

# Set up the detector with default parameters.
detector = cv2.SimpleBlobDetector_create()

# Detect blobs.
keypoints = detector.detect(im)

print (keypoints)

# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of the circle corresponds to the size of blob
im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

# Show keypoints
cv2.imshow("Keypoints", im_with_keypoints)
cv2.waitKey(0)

My code is working but the problem is how to detect spots? as in shown in the image.

Thanks in advance. Please suggest something

Edit-1

Error Getting

---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-11-2754358a7c43> in <module>()
----> 1 import PyDIP as dip
      2 import PyDIP.PyDIPviewer as dv

ModuleNotFoundError: No module named 'PyDIP'

I am trying to install PyDIP but not unbale.

krish
  • 69
  • 1
  • 4
  • 9
  • hello, are all violet spot WBC?? is it ok if we detect all such spots? – spaceman Sep 25 '18 at 19:06
  • The questions may help: https://stackoverflow.com/questions/47342025/how-to-detect-colored-patches-in-an-image-using-opencv/47343587#47343587 and https://stackoverflow.com/questions/10948589/choosing-the-correct-upper-and-lower-hsv-boundaries-for-color-detection-withcv/48367205#48367205 – Kinght 金 Sep 26 '18 at 00:40
  • @spaceman, I just need wbc only – krish Sep 26 '18 at 18:40
  • Krish, you need to build and install PyDIP from source before you can import it (it's new, we still don't have an official build that you can download). Follow the instructions in one of the `README` files, and if you then still have problems, let us know [here](https://github.com/DIPlib/diplib/issues). – Cris Luengo Sep 26 '18 at 19:16
  • @Cris Luengo, Thank you. Is any other way to do the same work? Build and install PyDIP will take time. – krish Sep 26 '18 at 19:35
  • Sorry, I just don't know OpenCV very well, but I'm sure you can accomplish this task also using OpenCV plus some standard NumPy functionality. – Cris Luengo Sep 26 '18 at 19:41
  • @Cris Luengo, Thank you for your help, can you please let me know how build and install PyDIP? I have installed all the dependencies software but not able to find `DIPlib.sln` as per shown in readme file – krish Sep 26 '18 at 19:49
  • I guess you are working on Windows then. You should follow the instructions in [README_Windows.md](https://github.com/DIPlib/diplib/blob/master/README_Windows.md). If any bits are not clear, please [submit an issue](https://github.com/DIPlib/diplib/issues). I'd be happy to improve the instructions there. – Cris Luengo Sep 26 '18 at 19:54

3 Answers3

1

I don't have OpenCV here, but use PyDIP instead (I'm an author).

The detection in this case is fairly trivial because of the different color and sizes of the cells. Spaceman suggested to use the HSV color space. That is a good idea, but since this is so simple, I'm going to just use the individual green and blue channels instead. The "wbc" cells are very dark in the green channel, but not in the blue one. Everything that is black (outside of the field of view, and your drawings) is dark in both channels. So detecting the "wbc" and the "platelet" cells is a matter of finding dark regions in the green channel that are not dark in the blue. Next, a simple size criterion will exclude the "platelet" cells.

Finally, to crop, I group nearby detections (as these seem to belong together), and crop the groups from the image:

import PyDIP as dip

img = dip.ImageReadTIFF('/home/cris/tmp/cells')

# detect wbc
mask = dip.Erosion(img.TensorElement(2), dip.SE(7, 'elliptic'))
wbc = (img.TensorElement(1) < 50) & (mask > 50) # threshold green and blue channels, exact threshold values don't matter, color differences are obvious
wbc = dip.Closing(wbc, dip.SE(15, 'elliptic')) # fills small holes
wbc = dip.Opening(wbc, dip.SE(25, 'elliptic')) # removes small cells

# group and find bounding boxes
labs = dip.Label(dip.BinaryDilation(wbc, 2, 50)) # 50 is the half the distance between detections that belong together
labs *= wbc
m = dip.MeasurementTool.Measure(labs, features=['Minimum','Maximum'])

# crop
margin = 10 # space to add around detections when cropping
for obj in m.Objects():
    left = int(m[obj]['Minimum'][0]) - margin
    right = int(m[obj]['Maximum'][0]) + margin
    top = int(m[obj]['Minimum'][1]) - margin
    bottom = int(m[obj]['Maximum'][1]) + margin
    crop = img[left:right, top:bottom]
    dip.ImageWriteTIFF(crop, '/home/cris/tmp/cells%d'%obj)

This leads to the following small images:

cells1 cells2 cells3

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • The library seems to be good...where can I find its documentation of inbuilt function?. – spaceman Sep 26 '18 at 00:12
  • 1
    @spaceman: the docs to the C++ library are [here](https://diplib.github.io/diplib-docs/). The Python bindings are thin wrappers, function and class names and behavior are identical to C++. There is also not yet much documentation visible within Python. The Python interface is quite new and needs some more work to be made more Python-like and simpler to use. We’ll be grateful for any contributions, whether they are bug reports, code fixes, new code, documentation, anything! :) – Cris Luengo Sep 26 '18 at 03:08
  • @Cris Luengo, How to install PyDIP? please let me know – krish Sep 26 '18 at 13:31
0

When you say your code is working, I assume that means you're already detecting what you want to detect, and your question about cropping is just that you want to get images of the detected spots.

If I got that right, then remember that OpenCV images are just numpy arrays, so all you need is a subset of that array. Does this do what you want?

blob_images = list()
for kp in keypoints:
    x, y, r = *kp.pt, kp.size
    crop = im[y-r:y+r, x-r:x+r]
    blob_images.append(crop)

Now you should have a list of cropped images. From there, you can filter them so you only get white blood cells or save them with cv2.imwrite() or do whatever you want.

Be warned that crop is just a view into the im array, not a separate copy. This saves memory, but modifying one will modify the other. Use im[y-r:y+r, x-r:x+r].copy() if you need to decouple them.

dirtbirb
  • 71
  • 10
  • The actual blob detection is more difficult - I would've commented to clarify, but I don't have that privilege yet... – dirtbirb Sep 25 '18 at 19:34
0

I try to your able image to detect WBC which are in violet color.

import cv2
import numpy as np;

# Read image
im = cv2.imread("image.jpg")
hsv = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)

I tried to convert it color space since i assume wbc's are always going to be in violet color. Since we have to detect object by color it better to convet it to other HSV color space you can read below link to know what HSV is below is output. cv2.imwrite("result1.jpg",hsv) enter image description here

gray_image = cv2.cvtColor(hsv, cv2.COLOR_BGR2GRAY)
cv2.imwrite("result2.jpg",gray_image)

enter image description here

res,thresh_img=cv2.threshold(gray_image,210,255,cv2.THRESH_BINARY_INV) 

Here 210 is the threshold grayscale value for getting the spots which are white in color i.e WBC's

im2, contours, hierarchy = cv2.findContours(thresh_img,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cv2.imwrite("result3.jpg",thresh_img)

enter image description here this image will all WBC's in black color. By using findContours we got the contours which are black in color.

count=0
original_image_copy=im.copy()    
for c in contours:
    area=cv2.contourArea(c)
    if area>10 and area<2500:
        (x,y),radius = cv2.minEnclosingCircle(c)
        center = (int(x),int(y))
        radius = int(radius)
        img = cv2.circle(im,center,radius,(0,255,0),10)
        cv2.circle(im,center,radius,(0,255,0),10)
        x, y, w, h = cv2.boundingRect(c)
        if w>20 and h>20:
            roi = original_image_copy[y:y+h, x:x+w]
            cv2.imwrite("images/roi"+str(count)+".jpg", roi) # make sure you have folder `images` in same folder in which you are running code.
        # cv2.drawContours(im, [c], 0,(0,255,0), 10)
cv2.imwrite("result4.jpg",im)

enter image description here I know this wont be the perfect answer but you can tryto remove some noise in corner of the circle by clicking image in different way or you can use image processing function like morphology operattions like dilation.

spaceman
  • 403
  • 4
  • 11