1

I am new to opencv but I need to analyze thermal images of mice (see example image). The idea is (1) to keep only one contour, e.g. the whole mouse (that works more or less well) and (2) separate this contour into the tail and the rest of the body to get two distinct contours. I have tried using thresholding, edge detection and watershed but the results are far from good. I thought about using the different shapes of tail vs body but I do not know how to accomplish that.

Is there a reliable way to do this that can also be generalized to similar images or even videos?

Thanks in advance

Nagas
  • 13
  • 2
  • I got the tail decently with threshold values `230,255`. It also gets small parts of the head, if all pictures are consistent, you can eliminate the head parts by eliminating contours below certain area (as the head contours are very small). Anything else I can think of will be quite complicated, though I'm not an expert. – Ahmet Feb 12 '20 at 12:03
  • Unfortunately, the images are not consistent due to fluctuations in surface temperatures over time/test subject. The final goal is to draw the two contours over multiple images without modifying parameters per image. – Nagas Feb 12 '20 at 14:06

2 Answers2

3

Using morphology as Cryckx mentioned is good, but you can also use Distance Transform, which will weaken the thin parts (like tale) so it can be cut easily. Here is the result I've got (I cropped the image just for better visualization):

enter image description here

Opencv C++ code:

Mat im1 = imread("E:/1/2.jpg", 0);
Mat im2, im3;

threshold(im1, im2, 250, 255, THRESH_OTSU);

imshow("Initial Thresholding", im2);

Mat dist;
distanceTransform(im2, dist, DIST_L2, 3);
normalize(dist, dist, 0, 255.0, NORM_MINMAX);
dist.convertTo(dist, CV_8U);

imshow("Distance Transform Image", dist);
Mat mask1, mask2, mask3;

threshold(dist, mask1, 50, 255,THRESH_BINARY); // A suitable threshold to cut the weak tale
dilate(mask1, mask1, Mat::ones(9,9, CV_8U));

imshow("Threshold on Distance Transform", mask1);

bitwise_and(im2, mask1, mask2);

imshow("mouse", mask2);

subtract(im2, mask2, mask3);

imshow("tale", mask3);
waitKey(0);
MeiH
  • 1,763
  • 11
  • 17
  • 1
    Brilliant use of the Distance Transform. Nice. – stateMachine Feb 13 '20 at 01:45
  • Thank you both for your solutions. Both methods work well on single images, but MH304's solution can be also easily implemented in analyzing videos, at least for me :-) – Nagas Feb 13 '20 at 10:18
2

Reliable methods for shape segmentation are using shape models. This paper gives a reasonable introduction : https://pdfs.semanticscholar.org/ebc2/ceba03a0f561dd2ab27c97b641c649c48a14.pdf . The idea would be to learn a statistical model from a set of images (mean mouse shape and the deformations around that mean shape.) Then you can use that model to do the segmentation by registering it to unseen shapes.

Just for fun I tried morphological math (erosion/dilatation) which seems to work quite well on your image :)

tail body

Python code used :

import numpy as np
import math
import cv2 as cv

mouse = cv.imread("mouse.jpg")
kernel7 = np.ones((7,7),np.uint8)
body = cv.morphologyEx(mouse, cv.MORPH_OPEN, kernel7)
bodyErrode = cv.dilate(body,kernel7)
mask= cv.bitwise_not( bodyErrode );
mask2, tr = cv.threshold(mask, 120, 255, cv.THRESH_BINARY) 
tail = cv.bitwise_and(mouse,tr)
cv.imshow("tail",tail)
cv.imshow('body',body)
cv.waitKey()
Cryckx
  • 659
  • 6
  • 18