finding area and centre of stones - matlab

I want to find area and center of these stones.
but some of them can not be found.
here are codes
I=imread('E:/2.png');
level = graythresh(I);
BW = im2bw(I,level);
se = strel('disk',2);
bw1 = imclose(BW,se);
bw1 = imfill(BW,'holes');
bwa=bwareaopen(bw1,25);
cc = bwconncomp(bwa)
stat = regionprops(cc,'centroid','Area');
ss=[stat.Area];
imshow(I); hold on;
for x = 1: numel(stat)
plot(stat(x).Centroid(1),stat(x).Centroid(2), 'wp','MarkerSize',6,'MarkerFaceColor','b');
end
figure, imshow(bwa)
result is here:
and this is black and white pic;
some of these stones can not be separated.
is there any idea for it?

Erode stones until you separated them, find segments via connected components (e.g. findContours), set centers, then apply flood fill seeding floods at the centers in the original BW image (before erosion) to gracefully define segments. “Gracefully” means that floods should not ‘leak' into another (possibly connected) segment since it will be already filled with a different label. You may want to play with the parameters of floodFIll to tune up your segmentation. I did not have time to do this.
// separate stones
Mat Ibw = imread("bw.png", 0);
imshow("bw", Ibw);
int w=Ibw.cols, h=Ibw.rows;
int ERODE_SZ = 20;
Mat kernel = getStructuringElement( cv::MORPH_RECT, Size(ERODE_SZ, ERODE_SZ));
Mat Ierode;
erode(Ibw, Ierode, kernel);
imshow("erode", Ierode); imwrite("erode.png", Ierode);
vector<vector<Point> > contours;
Mat hierarchy;
Mat Icc = Ierode.clone();
findContours(Icc, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
// find centers
Mat Icenters = Ibw.clone();
int sz = contours.size();
vector<Point> centers(sz);
for (int i=0; i<sz; ++i) {
if (i==0)
centers[i] = Point2f(0.f, 0.f);
int area = contours[i].size();
for (int j=0; j<area; j++) {
centers[i]+=contours[i][j];
}
centers[i]*=1.0/area;
circle(Icenters, centers[i], 3, 100, 3);
}
imshow("centers", Icenters);imwrite("erode.png", Ierode);
// find segments
Mat Iseg = Ibw.clone();
RNG rng( 0xFFFFFFFF );
for (int i=0; i<sz; ++i) {
floodFill(Iseg, centers[i], rng.uniform(100, 200));
circle(Iseg, centers[i], 3, 0, 1);
}
imshow("seg", Iseg); imwrite("result.png", Iseg);
waitKey();

Related

How to process image before applying bwlabel?

I = imread('Sub1.png');
figure, imshow(I);
I = imcomplement(I);
I = double(I)/255;
I = adapthisteq(I,'clipLimit',0.0003,'Distribution','exponential');
k = 12;
beta = 2;
maxIter = 100;
for i=1:length(beta)
[seg,prob,mu,sigma,it(i)] = ICM(I, k, beta(i), maxIter,5);
pr(i) = prob(end);
hold on;
end
figure, imshow(seg,[]);
and ICM function is defined as
function [segmented_image,prob,mu,sigma,iter] = ICM(image, k, beta, max_iterations, neigh)
[width, height, bands] = size(image);
image = imstack2vectors(image);
segmented_image = init(image,k,1);
clear c;
iter = 0;
seg_old = segmented_image;
while(iter < max_iterations)
[mu, sigma] = stats(image, segmented_image, k);
E1 = energy1(image,mu,sigma,k);
E2 = energy2(segmented_image, beta, width, height, k);
E = E1 + E2;
[p2,~] = min(E2,[],2);
[p1,~] = min(E1,[],2);
[p,segmented_image] = min(E,[],2);
prob(iter+1) = sum(p);
%find mismatch with previous step
[c,~] = find(seg_old~=segmented_image);
mismatch = (numel(c)/numel(segmented_image))*100;
if mismatch<0.1
iter
break;
end
iter = iter + 1;
seg_old = segmented_image;
end
segmented_image = reshape(segmented_image,[width height]);
end
Output of my algorithm is a logical matrix (seg) of size 305-by-305. When I use
imshow(seg,[]);
I am able to display the image. It shows different component with varying gray value. But bwlabel returns 1. I want to display the connected components. I think bwlabel thresholds the image to 1. unique(seg) returns values 1 to 10 since number of classes used in k-means is 10. I used
[label n] = bwlabel(seg);
RGB = label2rgb(label);
figure, imshow(RGB);
I need all the ellipse-like structures which are in between the two squares close to the middle of the image. I don't know the number of classes present in it.
Input image:
Ground truth:
My output:
If you want to explode the label image to different connected components you need to use a loop to extract labels for each class and sum label images to get the out label image.
u = unique(seg(:));
out = zeros(size(seg));
num_objs = 0;
for k = 1: numel(u)
mask = seg==u(k);
[L,N] = bwlabel(mask);
L(mask) = L(mask) + num_objs;
out = out + L;
num_objs = num_objs + N ;
end
mp = jet(num_objs);
figure,imshow(out,mp)
Something like this is produced:
I have tried to do everything out of scratch. I wish it is of some help.
I have a treatment chain that get at first contours with parameters tuned on a trial-and-error basis, I confess. The last "image" is given at the bottom ; with it, you can easily select the connected components and do for example a reconstruction by markers using "imreconstruct" operator.
clear all;close all;
I = imread('C:\Users\jean-marie.becker\Desktop\imagesJPG10\spinalchord.jpg');
figure,imshow(I);
J = I(:,:,1);% select the blue channel because jpg image
J=double(J<50);% I haven't inverted the image
figure, imshow(J);
se = strel('disk',5);
J=J-imopen(J,se);
figure, imshow(J);
J=imopen(J,ones(1,15));% privilegizes long horizontal strokes
figure, imshow(J);
K=imdilate(J,ones(20,1),'same');
% connects verticaly not-to-far horizontal "segments"
figure, imshow(K);

Triangle-like shape detection

I am currently working on a project for my university: detection of pollen in an RGB-image.
the orange stuff is what I want to have marked.
I managed to detect the circular-shaped ones using imfindcircles() but for the triangular shapes I did not find a function.
Im = imread('pollen10.jpg');
image_gray = rgb2gray(Im);
%% Detect circles with given radii
Rmin = 30;
Rmax = 160;
[centersDark, radiiDark] = imfindcircles(image_gray,[Rmin Rmax],'ObjectPolarity','dark','sensitivity',0.90);
%% Checking results
imshow(image_gray);
hold on
viscircles(centersDark, radiiDark,'LineStyle','-','Color','b','Linewidth',1);
hold off
How can I detect the triangular shapes?
I managed to get an bw-image where I want to count the white polygons. I did not find something easy for this by now, but I will invest more time in searching soon
im = imread('pollen10.jpg');
BW = im(:,:,1) < 140;
cc = bwconncomp(BW);
stats = regionprops(cc, 'Centroid','Area');
centroids = cat(1,stats.Centroid);
idx = find([stats.Area] > 100);
BW2 = ismember(labelmatrix(cc), idx);
CC2 = bwconncomp(BW2);
stats2 = regionprops(CC2, 'Centroid','Area','BoundingBox','Eccentricity');
centroids2 = cat(1,stats2.Centroid);
imshow(BW2)
hold on
plot(centroids2(:,1),centroids2(:,2),'b*');

How to do side filling of an image

We need to detect the ground using simple filling starting from the bottom of the image shown below. Any suggestions?
This codes what I have done so far,
rgb=imread('obstacle_scene_1.jpg');
figure, imshow(rgb);
rgbImage = imread('obstacle_scene_1.jpg');
hsvInt = rgb2hsv(rgbImage);
hsvDouble = rgb2hsv(double(rgbImage));
figure, imshow(hsvInt);
figure, imshow(hsvDouble);
level = graythresh(hsvInt);
bw = im2bw(hsvInt,level);
bw = bwareaopen(bw, 50);
figure, imshow(bw)
what I want is
Using GraphCut, constraining the top and the obstacles to "background" and the bottom to "foreground":
img = imread('http://i.stack.imgur.com/xJQBP.jpg');
bw = img(4:243,6:325,1) > 128 ;
sz = size(bw);
Create pixel-wise tendency not to belong to background, stronger tendency at the bottom
bgp = linspace(1,0,sz(1))'*ones(1,sz(2));
Constrain the last row not to belong to background
bgp(end,:) = 1000.*(1-bw(end,:));
Constraint top row and obstacles not to belong to "foreground":
fgp = 1000.*bw;
fgp(1,:) = 1000;
Create the graph (using sparse_adj_matrix):
[ii jj] = sparse_adj_matrix(sz, 1, 1);
sel = ii<jj;
ii=ii(sel);
jj=jj(sel);
W = sparse(ii, jj, double(bw(ii)==bw(jj)), numel(bw), numel(bw));
Using GraphCut to split the image:
gch = GraphCut('open',[bgp(:) fgp(:)]', 500*[0 1; 1 0], W+W' );
[gch L] = GraphCut('expand', gch);
gch = GraphCut('close', gch);
Resulting with:
L = reshape(L, sz);

MATLAB Rotation an Image in Frequency Domain [duplicate]

I've heard that it should be possible to do a lossless rotation on a jpeg image. That means you do the rotation in the frequency domain without an IDCT. I've tried to google it but haven't found anything. Could someone bring some light to this?
What I mean by lossless is that I don't lose any additional information in the rotation. And of course that's probably only possible when rotating multiples of 90 degrees.
You do not need to IDCT an image to rotate it losslessly (note that lossless rotation for raster images is only possible for angles that are multiples of 90 degrees).
The following steps achieve a transposition of the image, in the DCT domain:
transpose the elements of each DCT block
transpose the positions of each DCT block
I'm going to assume you can already do the following:
Grab the raw DCT coefficients from the JPEG image (if not, see here)
Write the coefficients back to the file (if you want to save the rotated image)
I can't show you the full code, because it's quite involved, but here's the bit where I IDCT the image (note the IDCT is for display purposes only):
Size s = coeff.size();
Mat result = cv::Mat::zeros(s.height, s.width, CV_8UC1);
for (int i = 0; i < s.height - DCTSIZE + 1; i += DCTSIZE)
for (int j = 0; j < s.width - DCTSIZE + 1; j += DCTSIZE)
{
Rect rect = Rect(j, i, DCTSIZE, DCTSIZE);
Mat dct_block = cv::Mat::Mat(coeff, rect);
idct_step(dct_block, i/DCTSIZE, j/DCTSIZE, result);
}
This is the image that is shown:
Nothing fancy is happening here -- this is just the original image.
Now, here's the code that implements both the transposition steps I mentioned above:
Size s = coeff.size();
Mat result = cv::Mat::zeros(s.height, s.width, CV_8UC1);
for (int i = 0; i < s.height - DCTSIZE + 1; i += DCTSIZE)
for (int j = 0; j < s.width - DCTSIZE + 1; j += DCTSIZE)
{
Rect rect = Rect(j, i, DCTSIZE, DCTSIZE);
Mat dct_block = cv::Mat::Mat(coeff, rect);
Mat dct_bt(cv::Size(DCTSIZE, DCTSIZE), coeff.type());
cv::transpose(dct_block, dct_bt); // First transposition
idct_step(dct_bt, j/DCTSIZE, i/DCTSIZE, result); // Second transposition, swap i and j
}
This is the resulting image:
You can see that the image is now transposed. To achieve proper rotation, you need to combine reflection with transposition.
EDIT
Sorry, I forgot that reflection is also not trivial. It also consists of two steps:
Obviously, reflect the positions of each DCT block in the required axis
Less obviously, invert (multiply by -1) each odd row OR column in each DCT block. If you're flipping vertically, invert odd rows. If you're flipping horizontally, invert odd columns.
Here's code that performs a vertical reflection after the transposition.
for (int i = 0; i < s.height - DCTSIZE + 1; i += DCTSIZE)
for (int j = 0; j < s.width - DCTSIZE + 1; j += DCTSIZE)
{
Rect rect = Rect(j, i, DCTSIZE, DCTSIZE);
Mat dct_block = cv::Mat::Mat(coeff, rect);
Mat dct_bt(cv::Size(DCTSIZE, DCTSIZE), coeff.type());
cv::transpose(dct_block, dct_bt);
// This is the less obvious part of the reflection.
Mat dct_flip = dct_bt.clone();
for (int k = 1; k < DCTSIZE; k += 2)
for (int l = 0; l < DCTSIZE; ++l)
dct_flip.at<double>(k, l) *= -1;
// This is the more obvious part of the reflection.
idct_step(dct_flip, (s.width - j - DCTSIZE)/DCTSIZE, i/DCTSIZE, result);
}
Here's the image you get:
You will note that this constitutes a rotation by 90 degrees counter-clockwise.

How to find Center of Mass for my entire binary image?

I'm interested in finding the coordinates (X,Y) for my whole, entire binary image, and not the CoM for each component seperatly.
How can I make it efficiently?
I guess using regionprops, but couldn't find the correct way to do so.
You can define all regions as a single region for regionprops
props = regionprops( double( BW ), 'Centroid' );
According to the data type of BW regionprops decides whether it should label each connected component as a different region or treat all non-zeros as a single region with several components.
Alternatively, you can compute the centroid by yourself
[y x] = find( BW );
cent = [mean(x) mean(y)];
Just iterate over all the pixels calculate the average of their X and Y coordinate
void centerOfMass (int[][] image, int imageWidth, int imageHeight)
{
int SumX = 0;
int SumY = 0;
int num = 0;
for (int i=0; i<imageWidth; i++)
{
for (int j=0; j<imageHeight; j++)
{
if (image[i][j] == WHITE)
{
SumX = SumX + i;
SumY = SumY + j;
num = num+1;
}
}
}
SumX = SumX / num;
SumY = SumY / num;
// The coordinate (SumX,SumY) is the center of the image mass
}
Extending this method to gray scale images in range of [0..255]: Instead of
if (image[i][j] == WHITE)
{
SumX = SumX + i;
SumY = SumY + j;
num = num+1;
}
Use the following calculation
SumX = SumX + i*image[i][j];
SumY = SumY + j*image[i][j];
num = num+image[i][j];
In this case a pixel of value 100 has 100 times higher weight than dark pixel with value 1, so dark pixels contribute a rather small fraction to the center of mass calculation.
Please note that in this case, if your image is large you might hit a 32 bits integer overflow so in that case use long int sumX, sumY variables instead of int.