11

My question is that: I have ROI's for the bounding boxes around the objects in an image. The ROI's are obtained by the Faster R-CNN. Now what I want is to apply the thresholding to get the object accurately contained within the bounding box. The ROI of this image was got by the Faster RCNN.

Test Image

So, After getting the ROI's, I only selected ROI from the image and pasted on the black image of the same size and dimension which result in the following image.let say

image containing only bounding boxes

As you can see that boxes are rectangular so in some places it covers some background area along with spikes. So, how can I apply thresholding to get only the spikes and other pixels turn to black?

EDIT: I've added the link to the ROI text file of the first image in the question

ROI file for first image

Faizan Khan
  • 573
  • 5
  • 20
  • could you also share the image files of the individual ROIs? It should be easier to do thresholding if you regard each image separately – mrk Aug 30 '19 at 07:09
  • Well, because we have coordinates for each ROI. So, you extract the roi from the whole image and perform processing. But how its going to help? – Faizan Khan Aug 30 '19 at 07:17
  • I understand that it is possible, I was asking you to share them. It would be easier to evaluate the result of your thresholding, it would be easier to label them, and so on. – mrk Aug 30 '19 at 07:24
  • 1
    Ok I try to edit the question with providing ROI for the first image in the question – Faizan Khan Aug 30 '19 at 07:28
  • Great, have you tried using a segmentation network from the start, instead of first using an object detector (see my answer)? Or are there any reasons that keep you from doing so? – mrk Aug 30 '19 at 07:30
  • Yes I know there is Mask R CNN for the purpose.. which can do object detection + segmenation. But the reason is that I didn't had data prepared for mask rcnn and other thing is that It is very slow. Though it is state of the art for this purpose – Faizan Khan Aug 30 '19 at 07:33
  • I would argue, that Mask R CNN is too big a hammer for the task at hand. There are better architectures for your purpose (such as U-Net). – mrk Aug 30 '19 at 07:37
  • 1
    I've edited the question and add a link to the ROI file for the first image in question. If you can help, that would be great. Thanks – Faizan Khan Aug 30 '19 at 07:40

3 Answers3

7

Color thresholding using cv2.inRange() should work here. I'm assuming you want to isolate the green area

Here's the main idea

  • Convert image to HSV format since it is easier to represent color than RBG
  • Perform color segmentation with a lower/upper threshold

You could also perform morphological operations to smooth or remove noise after obtaining the mask


enter image description here

import numpy as np
import cv2

image = cv2.imread('1.jpg')
result = image.copy()
image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower = np.array([18, 0, 0])
upper = np.array([179, 255, 255])
mask = cv2.inRange(image, lower, upper)
result = cv2.bitwise_and(result,result, mask=mask)
cv2.imshow('result', result)
cv2.imwrite('result.png', result)
cv2.waitKey()

You can use a HSV color thresholder script to isolate the desired color range

enter image description here

import cv2
import sys
import numpy as np

def nothing(x):
    pass

# Create a window
cv2.namedWindow('image')

# create trackbars for color change
cv2.createTrackbar('HMin','image',0,179,nothing) # Hue is from 0-179 for Opencv
cv2.createTrackbar('SMin','image',0,255,nothing)
cv2.createTrackbar('VMin','image',0,255,nothing)
cv2.createTrackbar('HMax','image',0,179,nothing)
cv2.createTrackbar('SMax','image',0,255,nothing)
cv2.createTrackbar('VMax','image',0,255,nothing)

# Set default value for MAX HSV trackbars.
cv2.setTrackbarPos('HMax', 'image', 179)
cv2.setTrackbarPos('SMax', 'image', 255)
cv2.setTrackbarPos('VMax', 'image', 255)

# Initialize to check if HSV min/max value changes
hMin = sMin = vMin = hMax = sMax = vMax = 0
phMin = psMin = pvMin = phMax = psMax = pvMax = 0

img = cv2.imread('1.jpg')
output = img
waitTime = 33

while(1):

    # get current positions of all trackbars
    hMin = cv2.getTrackbarPos('HMin','image')
    sMin = cv2.getTrackbarPos('SMin','image')
    vMin = cv2.getTrackbarPos('VMin','image')

    hMax = cv2.getTrackbarPos('HMax','image')
    sMax = cv2.getTrackbarPos('SMax','image')
    vMax = cv2.getTrackbarPos('VMax','image')

    # Set minimum and max HSV values to display
    lower = np.array([hMin, sMin, vMin])
    upper = np.array([hMax, sMax, vMax])

    # Create HSV Image and threshold into a range.
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower, upper)
    output = cv2.bitwise_and(img,img, mask= mask)

    # Print if there is a change in HSV value
    if( (phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
        print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
        phMin = hMin
        psMin = sMin
        pvMin = vMin
        phMax = hMax
        psMax = sMax
        pvMax = vMax

    # Display output image
    cv2.imshow('image',output)

    # Wait longer to prevent freeze for videos.
    if cv2.waitKey(waitTime) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()

Here's the result on the original image

enter image description here

nathancy
  • 26,679
  • 11
  • 67
  • 86
  • 1
    And if you skip the CNN and do the thresholding directly on the input image you’ll likely get a much better result. ;) – Cris Luengo Aug 27 '19 at 01:56
  • @nathancy yeah I've seen different morphological operations like erosion and dilation etc but couldn't get any better result with them. can you please provide some sample code that is working code for my case. Thanks for the help – Faizan Khan Aug 27 '19 at 05:08
  • @FaizanKhan, for this case I don't think there is a need to do morphological operations since you are not trying to extract any features or contours. There is a tradeoff from using these operations. For instance, eroding will remove noise but also remove details while dilating will enhance features but remove detail – nathancy Aug 27 '19 at 20:33
  • but I need spikes regions only. Apply color-based segmentation is just removing the background but I want to have spikes only. – Faizan Khan Aug 31 '19 at 03:24
  • I've accepted your answer. And if you have anything else in your mind that can further improve my solution please let me know and thanks for you time and help. If you found my question useful and valid, please upvote – Faizan Khan Sep 01 '19 at 02:59
5

In your TensorFlow detection, the output dictionary you get after you run the prediction has a field, "detection_scores".

output_dict = sess.run(tensor_dict,feed_dict={image_tensor: image})

Set a threshold on that,

 indexes=np.where(output_dict['detection_scores']>0.5)

Use the boxes, i.e. output_dict['detection_boxes'] only on those specific indexes which you filtered in the previous step.

[EDIT] Adding more code after the discussion in comments

#convert the image to hsv
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
#tune the numbers below accordingly
lower_green = np.array([60, 100, 50])
upper_green = np.array([60 , 255, 255])

mask = cv2.inRange(hsv, lower_green, upper_green)
res = cv2.bitwise_and(frame,frame, mask= mask)
#res has the output masked image

[EDIT] editing with the actual image given in the question

img=cv2.imread("idJyc.jpg")
lower_green = np.array([0, 10, 0])
upper_green = np.array([255 , 100, 255])
mask = cv2.inRange(img, lower_green, upper_green)
mask = np.abs(255-mask)
res = cv2.bitwise_and(img,img, mask=mask)
cv2.imshow("a",res)
cv2.waitKey(0)

Adding the output image for your reference.

enter image description here

venkata krishnan
  • 1,655
  • 1
  • 10
  • 19
  • Yes, I did that. But as you can see in the resultant image (2nd) we have rectangular boxes. What I want to do to apply thresholding within these boxes to get accurately the object and other pixels within the bounding boxes turn to black. – Faizan Khan Aug 21 '19 at 07:43
  • I think you miss understood my question. I already have ROI and based on these ROI's I pasted spikes areas on the black image but now I want to do the segmentation so I can get exactly the object and remaining pixels should turn black. – Faizan Khan Aug 21 '19 at 07:45
  • Then you must try mask RCNN. since you trained with boxes, you get the boxes, if you can train with the pixel level masks, the mask-RCNN will give you such results. – venkata krishnan Aug 21 '19 at 08:05
  • or simpler way is pixel masking based on the pixel value. Let's say if you want only the green pixels ignoring the rest, mask them by using opencv masking function for a specific color range. – venkata krishnan Aug 21 '19 at 08:06
  • yes. i understood the question now clearly, you can do a simple pixel level masking, or you can do some edge detection/contour detection to skip the background.but thats dangerous considering some images have whole of the green segment itself. – venkata krishnan Aug 21 '19 at 08:09
  • Yes, I'm looking for some solution like this either it is thresholding or some other method. Could you please write a code sample – Faizan Khan Aug 21 '19 at 08:09
  • well I used the provided code with lower and upper values for the green color but the whole image is turned into black @venkata krishnan – Faizan Khan Aug 21 '19 at 13:08
  • Yes. U need to update the values of the green color based on your pixel range you want to filter. I gave a simple example. – venkata krishnan Aug 22 '19 at 01:25
  • Yes i did that.. but Its not working for me. Should I apply this solution to each bounding box seperately? – Faizan Khan Aug 22 '19 at 01:27
  • 1
    edited the answer. please check now. i didnt convert to hsv. rather i masked with RGB itself. – venkata krishnan Aug 22 '19 at 01:55
  • YES!!!, it is working. Can you please tell is there any other way to improve the solution or can we do anything further with the resultant images to remove( turn black) the irrelevant stuff out of the image – Faizan Khan Aug 22 '19 at 04:39
  • you can further add edge detection or contour detection for individual blocks and take the contours. but in your case, since its highly noisy image i am not sure how well it works. If you find this answer useful, please mark this as accepted answer and feel free to upvote – venkata krishnan Aug 22 '19 at 04:48
  • 1
    Ok thanks.. I'm upvoting for now and waiting if some other person may also answer.. otherwise I'll mark your answer accepted – Faizan Khan Aug 22 '19 at 04:50
3

If you re familiar with applying neural networks and you re having enough data. This task is perfectly suited for segmentation.

I recommend U-Net, since it works with a small amount of labelled data for training. It is also fast, with few operations for this task with comparably low complexity. And has shown good performance on various tasks.

I also found a full code pipeline, in this case for heart segmentation in zebrafish, but in my opinion they did a good job explaining how to prepare the data (proposing labeling tools, etc.) and train the model.

Also taking a step back, you could also think of interpreting your task as a segmentation task from the beginning. Especially for the U-Net it shouldn't be a problem to segment multiple instances in the same image.

mrk
  • 5,654
  • 3
  • 41
  • 63
  • Does this will help in my case? As I'm already getting ROI for my images. So, can this be used as a next step or I have to do everything from start i.e preparing dataset for object detection + segmentation – Faizan Khan Aug 30 '19 at 07:31
  • This is definitely a solution. And I would argue with superior result, than any hand-crafted thresholding. As described you could either use the ROIs and train a segmentation network on them. Further I would argue, that you wouldnt necessarily need an object detector in the first place, but that's of course up to you and the requirements of your task. – mrk Aug 30 '19 at 07:33
  • well, how your solution can help me in a better solution. After getting ROI, how they can be used to get my desired solution. – Faizan Khan Aug 30 '19 at 07:39
  • Did you read my answer above this chat? The full code pipeline I linked, basically does what you want to do, just on another dataset. – mrk Aug 30 '19 at 07:43