Image Segmentation Techniques for Tracking Fish Wound
Here, I am going to briefly discuss the basic image processing automation tools and techniques that were used for locating a fish wound and determining its surface area and length. Please note, the methods that were used are not only limited to fish wounds but can be adapted for tracking different objects as well. A complete version of the Matlab code is available on Matlab Central File Exchange (http://www.mathworks.com/matlabcentral/fileexchange/43062).
The main problem was to process several hundreds of images and determine the area and length of a wound in each image. So, an automation technique and algorithm was required for saving huge manual computation time and also effectively getting the job done.
Figure 1: Image of a fish taken just after an acoustic tag insertion
The major work flow process was divided into:
- Determining scale (no. of pixels/cm)
- Tracking wound and plotting its surface area and length
Determining scale (no. of pixels/cm)
For automating scale determination, two red circles 3 cm apart (center to center) were attached on a standard ruler as shown in Figure 1. To save computation time the top right quarter portion of the original image consisting circles was cropped. For making the circles more distinct, the pixel intensity of the red color in the image was increased using imadjust function and then converted to a binary image. A 2-D median filter of [3 3] pixels window was applied to clear small noises. The radius range of the circle was determined using the measure distance tool provided in imtool function and finally, the circles were located by using imfindcircles function. The number of pixels between the centers of the two circles was plotted using imdistline function handle and its value was stored using iptgetapi function.
I = imread(filename); image_info = imfinfo(filename); cord = [image_info.Width/2 0 image_info.Width/2 image_info.Height/2]; Icr = imcrop(I,cord); Icr_red = imadjust(Icr,[.2 0.4 0.4; .9 .6 0.6],); Icr_gr = rgb2gray(Icr_red); Icr_gr = imadjust(Icr_gr); bw = im2bw(Icr_gr,0.2); bw = medfilt2(bw,[3 3]); bw = ~bw; radius_range = [185 195]; [center, radii] = imfindcircles(bw,radius_range,'ObjectPolarity','bright', ... 'Sensitivity',0.98); X = center(:,1); Y = center(:,2); imshow(Icr); viscircles(center,radii,'LineStyle','--'); hh = get(gcf,'CurrentAxes'); h = imdistline(hh,X,Y); api = iptgetapi(h); pixel_dist = getDistance(api)/3; pixel_area = pixel_dist*pixel_dist;
Figure 2: Locating circles and measuring pixel distance between their centers
Tracking wound and plotting its surface area and length
First, cropping of original image was done by the user creating a rectangle on the periphery of the wound using the imcrop function. Then the cropped image was adjusted by extracting the red pixel intensity and converted to a grayscale image. 2-D median filter of [9 9] pixels window was used to smooth the grayscale image. To convert the grayscale image into a binary image in such a way that only darker pixels were selected, a user defined threshold value that will hold true for multiple images was selected. The converted binary image may consist of some additional noises along with the wound track as shown in Figure 3. To clear up these unwanted detections, functions such as imclearborder and bwareaopen were used. Imclearborder clears up any detection that is touching the borderline and bwareaopen gets rid of any detection that is smaller than a given pixel area value. Finally, after cleaning up the unwanted detections, the pixel area of the wound was measured using regionprops function and converted to the standard scale by using above computed scale values. The boundary coordinates determined by bwboundaries function and a simple distance calculation between the coordinates was done to compute and plot the maximum length of the wound (Figure 4).
I = imread(filename); IG = rgb2gray(I); thresh = graythresh(IG); imcr = imcrop(I); imcr_red = imadjust(imcr,[.6 .4 .4; .9 .6 .6],); imcr_gr = rgb2gray(imcr_red); imcr_filt = medfilt2(imcr_gr,[9 9]); imbw = im2bw(imcr_filt,thresh-.025); imbw = ~imbw; imbw = imclearborder(imbw); imbw = bwareaopen(imbw,400); stats = regionprops(imbw,'Area'); area = stats.Area; area = area/pixel_area; [B,L] = bwboundaries(imbw,'noholes'); boundary = cell2mat(B); plot(boundary(:,2), boundary(:,1), 'r', 'LineWidth', 2)
Figure 3: Image adjustment by extracting the red pixels intensity and conversion into a binary image
Figure 4: Final wound image plot with calculated surface area and length