Matlab and ImageJ detecting bone fracture - matlab

I'm trying to detect a fracture in a picture using imageJ and Matlab, both of them are required. Here is the original image:
I already established the connection between matlab and imageJ and I've opened the image on imageJ and started by doing some things. First, I used the Find Edges function in imageJ menu to get an outline of the bone. After I did a constrast enhancement to enhance the outline. My problem now is, having only an outline and a black background how can I make an algorithm or something like it that will tell me that the lines don't connect? (meaning there is a fracture in the bone). I did something similar to what is on this video in the part when he ticks the sobel edge detection.
https://www.youtube.com/watch?v=Hxn2atZl5us

Gave it a shot in MATLAB only. You can use the Hough transform to find what the largest-contributing angles are to the edge-filtered image, then use that information to go one step more and detect where the break is with some typical image processing tricks.
No promises on how this will work on any images that are not the one that you provided, but the steps are reasonable to refine for additional sample breadth.
img = imread('http://i.stack.imgur.com/mHo7s.jpg');
ImgBlurSigma = 2; % Amount to denoise input image
MinHoughPeakDistance = 5; % Distance between peaks in Hough transform angle detection
HoughConvolutionLength = 40; % Length of line to use to detect bone regions
HoughConvolutionDilate = 2; % Amount to dilate kernel for bone detection
BreakLineTolerance = 0.25; % Tolerance for bone end detection
breakPointDilate = 6; % Amount to dilate detected bone end points
%%%%%%%%%%%%%%%%%%%%%%%
img = (rgb2gray(img)); % Load image
img = imfilter(img, fspecial('gaussian', 10, ImgBlurSigma), 'symmetric'); % Denoise
% Do edge detection to find bone edges in image
% Filter out all but the two longest lines
% This feature may need to be changed if break is not in middle of bone
boneEdges = edge(img, 'canny');
boneEdges = bwmorph(boneEdges, 'close');
edgeRegs = regionprops(boneEdges, 'Area', 'PixelIdxList');
AreaList = sort(vertcat(edgeRegs.Area), 'descend');
edgeRegs(~ismember(vertcat(edgeRegs.Area), AreaList(1:2))) = [];
edgeImg = zeros(size(img, 1), size(img,2));
edgeImg(vertcat(edgeRegs.PixelIdxList)) = 1;
% Do hough transform on edge image to find angles at which bone pieces are
% found
% Use max value of Hough transform vs angle to find angles at which lines
% are oriented. If there is more than one major angle contribution there
% will be two peaks detected but only one peak if there is only one major
% angle contribution (ie peaks here = number of located bones = Number of
% breaks + 1)
[H,T,R] = hough(edgeImg,'RhoResolution',1,'Theta',-90:2:89.5);
maxHough = max(H, [], 1);
HoughThresh = (max(maxHough) - min(maxHough))/2 + min(maxHough);
[~, HoughPeaks] = findpeaks(maxHough,'MINPEAKHEIGHT',HoughThresh, 'MinPeakDistance', MinHoughPeakDistance);
% Plot Hough detection results
figure(1)
plot(T, maxHough);
hold on
plot([min(T) max(T)], [HoughThresh, HoughThresh], 'r');
plot(T(HoughPeaks), maxHough(HoughPeaks), 'rx', 'MarkerSize', 12, 'LineWidth', 2);
hold off
xlabel('Theta Value'); ylabel('Max Hough Transform');
legend({'Max Hough Transform', 'Hough Peak Threshold', 'Detected Peak'});
% Locate site of break
if numel(HoughPeaks) > 1;
BreakStack = zeros(size(img, 1), size(img, 2), numel(HoughPeaks));
% Convolute edge image with line of detected angle from hough transform
for m = 1:numel(HoughPeaks);
boneKernel = strel('line', HoughConvolutionLength, T(HoughPeaks(m)));
kern = double(bwmorph(boneKernel.getnhood(), 'dilate', HoughConvolutionDilate));
BreakStack(:,:,m) = imfilter(edgeImg, kern).*edgeImg;
end
% Take difference between convolution images. Where this crosses zero
% (within tolerance) should be where the break is. Have to filter out
% regions elsewhere where the bone simply ends.
brImg = abs(diff(BreakStack, 1, 3)) < BreakLineTolerance*max(BreakStack(:)) & edgeImg > 0;
[BpY, BpX] = find(abs(diff(BreakStack, 1, 3)) < BreakLineTolerance*max(BreakStack(:)) & edgeImg > 0);
brImg = bwmorph(brImg, 'dilate', breakPointDilate);
brReg = regionprops(brImg, 'Area', 'MajorAxisLength', 'MinorAxisLength', ...
'Orientation', 'Centroid');
brReg(vertcat(brReg.Area) ~= max(vertcat(brReg.Area))) = [];
% Calculate bounding ellipse
brReg.EllipseCoords = zeros(100, 2);
t = linspace(0, 2*pi, 100);
brReg.EllipseCoords(:,1) = brReg.Centroid(1) + brReg.MajorAxisLength/2*cos(t - brReg.Orientation);
brReg.EllipseCoords(:,2) = brReg.Centroid(2) + brReg.MinorAxisLength/2*sin(t - brReg.Orientation);
else
brReg = [];
end
% Draw ellipse around break location
figure(2)
imshow(img)
hold on
colormap('gray')
if ~isempty(brReg)
plot(brReg.EllipseCoords(:,1), brReg.EllipseCoords(:,2), 'r');
end
hold off

Related

Find overlap area of two images with matlab

I want to find the overlap area of the two images using matlab.
If your ultimate goal is to stitch a panorama, you might want to consider this code.
In any case, to get the overlap area, you need to register the images first (find out, HOW they overlap - or more mathematically speaking: Find the transformation from image 1 to image 2). To do so you need to find matching points in both images.
The code below does that for two images (inspired by this code, which uses older MATLAB functions).
%% >>>>>>> load images and calculate their transformation <<<<<<< %%
im1 = imread('1.png');
im2 = imread('2.png');
imshowpair(im1, im2, 'montage');
% calculate features on grayscale image
im1g = rgb2gray(im1);
im2g = rgb2gray(im2);
points1 = detectSURFFeatures(im1g);
[features1, points1] = extractFeatures(im1g, points1);
points2 = detectSURFFeatures(im2g);
[features2, points2] = extractFeatures(im2g, points2);
% Find correspondences between im1 and im2
indexPairs = matchFeatures(features1, features2, 'Unique', true);
matchedPoints1 = points1(indexPairs(:,1), :);
matchedPoints2 = points2(indexPairs(:,2), :);
% Identity transformation
transform_eye = projective2d(eye(3));
% Estimate the transformation between im1 and im2
% we use a 'similarity' transform (translation/rotation), which treats the
% images as rigid bodys. 'affine' / 'projective' transformations allow for
% warping the images itself (the overlap might not be a rectangle).
transform = estimateGeometricTransform(matchedPoints1, matchedPoints2,...
'similarity', 'Confidence', 99.9, 'MaxNumTrials', 2000);
%% >>>>>>> apply transformation to images <<<<<<< %%
% create a world coordinate system (RF) that has space to store
% the reference image (im1) and the transformed image (im2)
R2 = imref2d(size(im2));
[~, R2T]=imwarp(im2,R2,transform);
xLimits=[min(0.5,R2T.XWorldLimits(1)) max(size(im1,2), R2T.XWorldLimits(2))];
yLimits=[min(0.5,R2T.YWorldLimits(1)) max(size(im1,1), R2T.YWorldLimits(2))];
width = round(xLimits(2) - xLimits(1));
height = round(yLimits(2) - yLimits(1));
RF = imref2d([height width], xLimits, yLimits);
% transform both images with regard to the world coordinate system RF
im1t=imwarp(im1,transform_eye,'OutputView',RF); % im1 stays in place (identity transform)
im2t=imwarp(im2,transform,'OutputView',RF); % im2 is transformed
% visualize result
imOverlay = im1t/2 + im2t/2;
imshow(imOverlay);
%% >>>>>>> get the overlap area only <<<<<<< %%
% if you only want the overlap area, apply the transform to image masks
im1bw = ones(size(im1)); % mask1
im2bw = ones(size(im2)); % mask2
im1bwt=imwarp(im1bw,transform_eye,'OutputView',RF); % im1 stays in place (identity transform)
im2bwt=imwarp(im2bw,transform,'OutputView',RF); % im2 is transformed
% visualize result
maskOverlap = im1bwt + im2bwt - 1;
imshow(maskOverlap);
% maskOverlap is a bw image that contains 'true' for overlap pixels
% you can use that for cropping imOverlay or
% use bwarea or regionprops to calculate the area

Speed up coloring segments of a spline curve?

I am trying to color segments of a spline curve with different RGB values. Many thanks to #Suever, I have a working version:
x = [0.16;0.15;0.25;0.48;0.67];
y = [0.77;0.55;0.39;0.22;0.21];
spcv = cscvn([x, y].'); % spline curve
N = size(x, 1);
figure;
hold on;
for idx = 1:N-2
before = get(gca, 'children'); % before plotting this segment
fnplt(spcv, spcv.breaks([idx, idx+1]), 2);
after = get(gca, 'children'); % after plotting this segment
new = setdiff(after, before);
set(new, 'Color', [idx/N, 1-idx/N, 0, idx/N]); % set new segment to a specific RGBA color
end
hold off;
Now I am looking to speed it up. Is it possible?
No explicit benchmarks per se, but you can vectorise this easily by
a. collecting the plotted points and dividing them into 'segments' (e.g. using the buffer function)
b. setting the 'color' property of the Children (thanks to #Suever for pointing out this can be done on an array of object handles directly)
%% Get spline curve
x = [0.16; 0.15; 0.25; 0.48; 0.67];
y = [0.77; 0.55; 0.39; 0.22; 0.21];
spcv = cscvn ([x, y].');
%% Split into segments
pts = fnplt (spcv); xpts = pts(1,:).'; ypts = pts(2,:).';
idx = buffer ([1 : length(xpts)]', 10, 1, 'nodelay'); % 10pt segments
lastidx=idx(:,end); lastidx(lastidx==0)=[]; idx(:,end)=[]; % correct last segment
% Plot segments
plot (xpts(idx), ypts(idx), xpts(lastidx), ypts(lastidx), 'linewidth', 10);
% Adjust colour and transparency
Children = flipud (get (gca, 'children'));
Colours = hsv (size (Children, 1)); % generate from colourmap
Alphas = linspace (0, 1, length (Children)).'; % for example
set (Children, {'color'}, num2cell([Colours, Alphas],2));
Note: As also pointed out in the comments section (thanks #Dev-iL), setting the colour to an RGBA quadruplet the way you ask (i.e. as opposed to a simple RGB triplet) is a newer (also, for now, undocumented) Matlab feature. This code, e.g. will not work in 2013b.

How to perform hough transform on canny edge image

After some pre- processing, edge detection and thinning i got the following image and the image is of type double
and in order to remove the isolated pixels within regions i used dilation as
se90 = strel('line', 2, 90);
se0 = strel('line', 2, 0);
BWsdil = imdilate(Edge, [se90 se0]);
vertical dilation followed by horizontal dilation
Actually i want to segment the objects which is labeled within rectangle(ellipse-like structure).
It is noticed that the black rectangle are ruptured during dilation
if i increase the threshold i will lose the segment in the bottom rectangle.
If i'm proceed with this result i'm end up in an error and even basic segmentation algorithms are not working without preprocessing. please help
Can your suggest any other technique to improve mask
if i do connected component analysis on gradient image.i will get border of ellipse instead of ellipse as shown
i tried hough transform but i'm getting some bad results
close all;clear all
I=imread('Sub1.png');
load edge
rotI = imrotate(I,33,'crop');
[H,T,R] = hough(Edge);
imshow(H,[],'XData',T,'YData',R,...
'InitialMagnification','fit');
xlabel('\theta'), ylabel('\rho');
axis on, axis normal, hold on;
P = houghpeaks(H,25,'threshold',ceil(0.3*max(H(:))));
x = T(P(:,2)); y = R(P(:,1));
plot(x,y,'s','color','white');
lines = houghlines(Edge,T,R,P,'FillGap',5,'MinLength',7);
figure, imshow(rotI), hold on
max_len = 0;
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');
% Plot beginnings and ends of lines
plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');
% Determine the endpoints of the longest line segment
len = norm(lines(k).point1 - lines(k).point2);
if ( len > max_len)
max_len = len;
xy_long = xy;
end
end

how to detect optic disc in retinal images using matlab

enter code here
% Finding mean for 49*49 sub images
meanmat=ones(209,209);
k=1;count=1;
[m n]=size(BW);
for i=25:1:m-24
for j=25:1:n-24
rowst=i-24;rowend=i+24;
colst=j-24;
colend=j+24;
summat=0;
for row=rowst:1:rowend
for col=colst:1:colend
summat=summat+BW(row,col);
end
end
meanval=(summat)/(49*49);
meanmat(k,count)=meanval;
if(count>208)
count=1;k=k+1;
else
count=count+1;
end
end
end
% mean and median filter
I = im2double(BW);
kernel = ones(80,80) / (80*80); % 49*49 mean kernel
J = conv2(I, kernel, 'same'); % Convolve keeping size of I
stdDevImage = stdfilt(BW);
varianceIMage = stdDevImage .^2;
figure,subplot(2,2,1);
imshow(BW);title('Original');
subplot(2,2,2);
imshow(meanmat);title(sprintf('MeanImage'));
subplot(2,2,3);
imshow(varianceIMage);title(sprintf('variance using stdfilt'));
subplot(2,2,4);
imshow(J);title(sprintf('Average Variance using conv2'));
I have calculated mean,variance and average variance for the image using the above code.But the optic disc was not detected properly.Can anyone help me with the matlab code for finding the optic disc?
%% Initial Image Processing.
% get image and mode from workspace
Im = evalin('base','Im');
singlemode = evalin('base','singlemode');
% apply filter on green component
f1 = fspecial('average',31); % create averaging filter
IMA = imadjust(Im(:,:,2)); % adjust green component intensity first
Imf = filter2(f1,IMA); % apply filter
Imf = mat2gray(Imf); % convert back from (0,1) to (0,255)
axes(handles.axes2); % show grayscale filtered image
imshow(Imf);
%% Edge Detection.
thrsh = str2num(get(handles.edit1,'String')); % default = 0.98
Ibw=im2bw(Imf,thrsh); % binary mask / black & white threshold
I_edge = edge(Ibw); % edge detection
% axes(handles.axes3);
% imshow(I_edge); % show image
%% Circular Hough transform to detect optical disc (OD).
% Rmin = str2num(get(handles.edit3,'String')); % minimum radius from user input
% Rmax = str2num(get(handles.edit4,'String')); % maximum radius from user input
Rmin = 80;
Rmax = 120;
radii = Rmin:5:Rmax; % radii to check
h = circle_hough(I_edge,radii,'same','normalise');
peaks = circle_houghpeaks(h,radii,'nhoodxy',2*(Rmax/2)+1,'nhoodr',5,'npeaks',1); % find the peaks in the transform, meaning find the best fit of a circle. and we only want 1 circle.
% Lines 196 -207 - if we're in single mode, we're plotting the circle in the top left image
if singlemode
axes(handles.axes1);
imshow(Im);
hold on
for peak = peaks
[x y] = circlepoints(peak(3)); % This function returns the x,y coordinates of the found circle, peak(3) is the radius of the found circle.
plot(x+peak(1),y+peak(2),'b-'); % we plot the x,y coordinates shifted by the center of the circle, which are peak(1) and peak(2)
end
plot(peak(1),peak(2),'r+'); % We plot the center of the circle with a red cross.
hold off
end
axes(handles.axes2); % Lines 208 - 214, we repeat the plot of the circle into axes2, the top right figure
hold on
for peak = peaks
[x y] = circlepoints(peak(3));
plot(x+peak(1),y+peak(2),'b-');
end
hold off
%% Region of Interest (ROI) Processing.
% we have localized the OD, define the ROI around this position for further
% processing.
axes(handles.axes2); % Activate axes2.
e = imellipse(gca,[peak(1)-2*peak(3) peak(2)-2*peak(3) 4*peak(3) 4*peak(3)]); %get an elliptical sub image centered around the peak(1) and peak(2) values (the centers of the previously found OD) and 2 times the radius that was found previously.
BW = createMask(e); % Create a mask from this region of interest = ROI.
Imf_masked = Imf.*BW; % Apply mask to the image, this will make everything outside of the ROI become black.
% axes(handles.axes4);
% imshow(Imf_masked);
thrsh = str2num(get(handles.edit5,'String')); % get threshold for ROI hough transform from the GUI, default = 0.65
Ibw=im2bw(Imf_masked,thrsh); % binary mask / black & white threshold (threshold the masked image).
I_edge = edge(Ibw); % edge detection
% axes(handles.axes3);
% imshow(I_edge); % show image
% hough transform to find circle in the ROI
h = circle_hough(I_edge,radii,'same','normalise');
peaks = circle_houghpeaks(h,radii,'nhoodxy',2*(Rmax/2)+1,'nhoodr',5,'npeaks',1);
if singlemode
axes(handles.axes1);
hold on
for peak = peaks
[x y] = circlepoints(peak(3));
plot(x+peak(1),y+peak(2),'g-');
end
plot(peak(1),peak(2),'g+');
hold off
end

Drawing the major and minor axis of an elliptical object in MATLAB

This program currently inputs an image of a coin, thresholds it, binarizes it, and finds the major and minor axis lengths of the segmented elliptical using the regionprops function. How do I output a subplot where I draw the axes used to calculate the 'MajorAxisLength' and 'MinorAxisLength' over the original image?
I have appended my code for your perusal.
% Read in the image.
folder = 'C:\Documents and Settings\user\My Documents\MATLAB\Work';
baseFileName = 'coin2.jpg';
fullFileName = fullfile(folder, baseFileName);
fullFileName = fullfile(folder, baseFileName);
if ~exist(fullFileName, 'file')
fullFileName = baseFileName; % No path this time.
if ~exist(fullFileName, 'file')
%Alert user.
errorMessage = sprintf('Error: %s does not exist.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
rgbImage = imread(fullFileName);
% Get the dimensions of the image. numberOfColorBands should be = 3.
[rows columns numberOfColorBands] = size(rgbImage);
% Display the original color image.
subplot(2, 3, 1);
imshow(rgbImage, []);
title('Original color Image', 'FontSize', fontSize);
% Enlarge figure to full screen.
set(gcf, 'Position', get(0,'Screensize'));
% Extract the individual red color channel.
redChannel = rgbImage(:, :, 1);
% Display the red channel image.
subplot(2, 3, 2);
imshow(redChannel, []);
title('Red Channel Image', 'FontSize', fontSize);
% Binarize it
binaryImage = redChannel < 100;
% Display the image.
subplot(2, 3, 3);
imshow(binaryImage, []);
title('Thresholded Image', 'FontSize', fontSize);
binaryImage = imfill(binaryImage, 'holes');
labeledImage = bwlabel(binaryImage);
area_measurements = regionprops(labeledImage,'Area');
allAreas = [area_measurements.Area];
biggestBlobIndex = find(allAreas == max(allAreas));
keeperBlobsImage = ismember(labeledImage, biggestBlobIndex);
measurements = regionprops(keeperBlobsImage,'MajorAxisLength','MinorAxisLength')
% Display the original color image with outline.
subplot(2, 3, 4);
imshow(rgbImage);
hold on;
title('Original Color Image with Outline', 'FontSize',fontSize);
boundaries = bwboundaries(keeperBlobsImage);
blobBoundary = boundaries{1};
plot(blobBoundary(:,2), blobBoundary(:,1), 'g-', 'LineWidth', 1);
hold off;
I had the same task as you for some project I did 2 years ago. I've modified the code I used then for you below. It involved calculating the covariance matrix for the datapoints and finding their eigenvalues/eigenvectors. Note here that because of circular symmetry, the minor and major axis will be somewhat "random". Also note that I have made the image binary in a very naïve way to keep the code simple.
% Load data and make bw
clear all;close all; clc;
set(0,'Defaultfigurewindowstyle','docked')
I = imread('american_eagle_gold_coin.jpg');
Ibw = im2bw(I,0.95);
Ibw = not(Ibw);
figure(1);clf
imagesc(Ibw);colormap(gray)
%% Calculate axis and draw
[M N] = size(Ibw);
[X Y] = meshgrid(1:N,1:M);
%Mass and mass center
m = sum(sum(Ibw));
x0 = sum(sum(Ibw.*X))/m;
y0 = sum(sum(Ibw.*Y))/m;
%Covariance matrix elements
Mxx = sum(sum((X-x0).^2.*Ibw))/m;
Myy = sum(sum((Y-y0).^2.*Ibw))/m;
Mxy = sum(sum((Y-y0).*(X-x0).*Ibw))/m;
MM = [Mxx Mxy; Mxy Myy];
[U S V] = svd(MM);
W = V(:,1)/sign(V(1,1)); %Extremal directions (normalized to have first coordinate positive)
H = V(:,2);
W = 2*sqrt(S(1,1))*W; %Scaling of extremal directions to give ellipsis half axis
H = 2*sqrt(S(2,2))*H;
figure(1)
hold on
plot(x0,y0,'r*');
quiver(x0,y0,W(1),H(1),'r')
quiver(x0,y0,W(2),H(2),'r')
hold off
Look at the documentation for the Orientation attribute that regionprops() can return to you.
This gives the angle between the positive x-axis and the major axis of the ellipse. You should be able to derive the equation for the major axis line in terms of that angle, and then just make a grid of x-axis points, and compute the major axis line's value for all the points in your grid, then just plot it like you would plot any other curve in MATLAB.
To do the same for the minor axis, just note that it will be 90 degrees further counter-clockwise from the major axis, then repeat the step above.
Usually one does it with computing eigenvectors, as explained in the Wikipedia article Image moment under 'examples'. That would be the correct way.
But I wonder, if you know the centroid and the boundingbox from MATLAB, then the endpoint of the major axis must be in the upper left or upper right corner. So checking (apart from noise) these two corners, if there are pixel, would give you the major axis. The minor axis then is just orthogonal to it with respect to the centroid.
Sorry for not having MATLAB code ready.
The reasoning is not that wrong, but not so good either, using the orientation as written above is better ;)