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.
Related
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.
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();
This is part of a code from spectral subtraction algorithm,i'm trying to optimize it for android.please help me.
this is the matlab code:
function Seg=segment(signal,W,SP,Window)
% SEGMENT chops a signal to overlapping windowed segments
% A= SEGMENT(X,W,SP,WIN) returns a matrix which its columns are segmented
% and windowed frames of the input one dimentional signal, X. W is the
% number of samples per window, default value W=256. SP is the shift
% percentage, default value SP=0.4. WIN is the window that is multiplied by
% each segment and its length should be W. the default window is hamming
% window.
% 06-Sep-04
% Esfandiar Zavarehei
if nargin<3
SP=.4;
end
if nargin<2
W=256;
end
if nargin<4
Window=hamming(W);
end
Window=Window(:); %make it a column vector
L=length(signal);
SP=fix(W.*SP);
N=fix((L-W)/SP +1); %number of segments
Index=(repmat(1:W,N,1)+repmat((0:(N-1))'*SP,1,W))';
hw=repmat(Window,1,N);
Seg=signal(Index).*hw;
and this is our java code for this function:
public class MatrixAndSegments
{
public int numberOfSegments;
public double[][] res;
public MatrixAndSegments(int numberOfSegments,double[][] res)
{
this.numberOfSegments = numberOfSegments;
this.res = res;
}
}
public MatrixAndSegments segment (double[] signal_in,int samplesPerWindow, double shiftPercentage, double[] window)
{
//default shiftPercentage = 0.4
//default samplesPerWindow = 256 //W
//default window = hanning
int L = signal_in.length;
shiftPercentage = fix(samplesPerWindow * shiftPercentage); //SP
int numberOfSegments = fix ( (L - samplesPerWindow)/ shiftPercentage + 1); //N
double[][] reprowMatrix = reprowtrans(samplesPerWindow,numberOfSegments);
double[][] repcolMatrix = repcoltrans(numberOfSegments, shiftPercentage,samplesPerWindow );
//Index=(repmat(1:W,N,1)+repmat((0:(N-1))'*SP,1,W))';
double[][] index = new double[samplesPerWindow+1][numberOfSegments+1];
for (int x = 1; x < samplesPerWindow+1; x++ )
{
for (int y = 1 ; y < numberOfSegments + 1; y++) //numberOfSegments was 3
{
index[x][y] = reprowMatrix[x][y] + repcolMatrix[x][y];
}
}
//hamming window
double[] hammingWindow = this.HammingWindow(samplesPerWindow);
double[][] HW = repvector(hammingWindow, numberOfSegments);
double[][] seg = new double[samplesPerWindow][numberOfSegments];
for (int y = 1 ; y < numberOfSegments + 1; y++)
{
for (int x = 1; x < samplesPerWindow+1; x++)
{
seg[x-1][y-1] = signal_in[ (int)index[x][y]-1 ] * HW[x-1][y-1];
}
}
MatrixAndSegments Matrixseg = new MatrixAndSegments(numberOfSegments,seg);
return Matrixseg;
}
public int fix(double val) {
if (val < 0) {
return (int) Math.ceil(val);
}
return (int) Math.floor(val);
}
public double[][] repvector(double[] vec, int replications)
{
double[][] result = new double[vec.length][replications];
for (int x = 0; x < vec.length; x++) {
for (int y = 0; y < replications; y++) {
result[x][y] = vec[x];
}
}
return result;
}
public double[][] reprowtrans(int end, int replications)
{
double[][] result = new double[end +1][replications+1];
for (int x = 1; x <= end; x++) {
for (int y = 1; y <= replications; y++) {
result[x][y] = x ;
}
}
return result;
}
public double[][] repcoltrans(int end, double multiplier, int replications)
{
double[][] result = new double[replications+1][end+1];
for (int x = 1; x <= replications; x++) {
for (int y = 1; y <= end ; y++) {
result[x][y] = (y-1)*multiplier;
}
}
return result;
}
public double[] HammingWindow(int size)
{
double[] window = new double[size];
for (int i = 0; i < size; i++)
{
window[i] = 0.54-0.46 * (Math.cos(2.0 * Math.PI * i / (size-1)));
}
return window;
}
"Porting" Matlab code statement by statement to Java is a bad approach.
Data is rarely manipulated in Matlab using loops and addressing individual elements (because the Matlab interpreter/VM is rather slow), but rather through calls to block processing functions (which have been carefully written and optimized). This leads to a very idiosyncratic programming style in which repmat, reshape, find, fancy indexing et al. are used to do operations which would be much more naturally expressed through Java loops.
For example, to multiply each column of a matrix A by a vector v, you will write in matlab:
A = diag(v) * A
or
A = repmat(v', 1, size(A, 2)) .* A
This solution:
for i = 1:size(A, 2),
A(:, i) = A(:, i) .* v';
end;
is inefficient.
But it would be terribly foolish to try to do the same thing in Java and invoke a matrix product or to build a matrix with repeated copies of v. Instead, just do:
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
a[i][j] *= v[i]
}
}
I suggest you to try to understand what this matlab function is actually doing, instead of focusing on how it is doing it, and reimplement it from scratch in Java, forgetting all the matlab implementation except the specifications given in the comments. Half of the code you have written is useless, indeed. Actually, it seems to me that this function wouldn't be needed at all, and what it does could be efficiently integrated in the caller's code.
I need to calculate the perceptual hash of an image and should do it without using any external libraries.
I tried using pHash (http://phash.org/) but I wasn't able to compile it for iOS (5) and I haven't found a real tutorial on how to do it.
One (library-dependent) solution is to use the pHashing functionality added to ImageMagick in version 6.8.8.3, which has iOS binaries available. Usage examples are documented here.
Here's also a simple reference function (in C#) for generating your own comparable image average hash, found on this blog.
public static ulong AverageHash(System.Drawing.Image theImage)
// Calculate a hash of an image based on visual characteristics.
// Described at http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html
{
// Squeeze the image down to an 8x8 image.
// Chant the ancient incantations to create the correct data structures.
Bitmap squeezedImage = new Bitmap(8, 8, PixelFormat.Format32bppRgb);
Graphics drawingArea = Graphics.FromImage(squeezedImage);
drawingArea.CompositingQuality = CompositingQuality.HighQuality;
drawingArea.InterpolationMode = InterpolationMode.HighQualityBilinear;
drawingArea.SmoothingMode = SmoothingMode.HighQuality;
drawingArea.DrawImage(theImage, 0, 0, 8, 8);
byte[] grayScaleImage = new byte[64];
uint averageValue = 0;
ulong finalHash = 0;
// Reduce to 8-bit grayscale and calculate the average pixel value.
for(int y = 0; y < 8; y++)
{
for(int x = 0; x < 8; x++)
{
Color pixelColour = squeezedImage.GetPixel(x,y);
uint grayTone = ((uint)((pixelColour.R * 0.3) + (pixelColour.G * 0.59) + (pixelColour.B * 0.11)));
grayScaleImage[x + y*8] = (byte)grayTone;
averageValue += grayTone;
}
}
averageValue /= 64;
// Return 1-bits when the tone is equal to or above the average,
// and 0-bits when it's below the average.
for(int k = 0; k < 64; k++)
{
if(grayScaleImage[k] >= averageValue)
{
finalHash |= (1UL << (63-k));
}
}
return finalHash;
}
I have an image of connected components(circles filled).If i want to segment them i can use watershed algorithm.I prefer writing my own function for watershed instead of using the inbuilt function in OPENCV.I have successfu How do i find the regionalmax of objects using opencv?
I wrote a function myself. My results were quite similar to MATLAB, although not exact. This function is implemented for CV_32F but it can easily be modified for other types.
I mark all the points that are not part of a minimum region by checking all the neighbors. The remaining regions are either minima, maxima or areas of inflection.
I use connected components to label each region.
I check each region for any point belonging to a maxima, if yes then I push that label into a vector.
Finally I sort the bad labels, erase all duplicates and then mark all the points in the output as not minima.
All that remains are the regions of minima.
Here is the code:
// output is a binary image
// 1: not a min region
// 0: part of a min region
// 2: not sure if min or not
// 3: uninitialized
void imregionalmin(cv::Mat& img, cv::Mat& out_img)
{
// pad the border of img with 1 and copy to img_pad
cv::Mat img_pad;
cv::copyMakeBorder(img, img_pad, 1, 1, 1, 1, IPL_BORDER_CONSTANT, 1);
// initialize binary output to 2, unknown if min
out_img = cv::Mat::ones(img.rows, img.cols, CV_8U)+2;
// initialize pointers to matrices
float* in = (float *)(img_pad.data);
uchar* out = (uchar *)(out_img.data);
// size of matrix
int in_size = img_pad.cols*img_pad.rows;
int out_size = img.cols*img.rows;
int x, y;
for (int i = 0; i < out_size; i++) {
// find x, y indexes
y = i % img.cols;
x = i / img.cols;
neighborCheck(in, out, i, x, y, img_pad.cols); // all regions are either min or max
}
cv::Mat label;
cv::connectedComponents(out_img, label);
int* lab = (int *)(label.data);
in = (float *)(img.data);
in_size = img.cols*img.rows;
std::vector<int> bad_labels;
for (int i = 0; i < out_size; i++) {
// find x, y indexes
y = i % img.cols;
x = i / img.cols;
if (lab[i] != 0) {
if (neighborCleanup(in, out, i, x, y, img.rows, img.cols) == 1) {
bad_labels.push_back(lab[i]);
}
}
}
std::sort(bad_labels.begin(), bad_labels.end());
bad_labels.erase(std::unique(bad_labels.begin(), bad_labels.end()), bad_labels.end());
for (int i = 0; i < out_size; ++i) {
if (lab[i] != 0) {
if (std::find(bad_labels.begin(), bad_labels.end(), lab[i]) != bad_labels.end()) {
out[i] = 0;
}
}
}
}
int inline neighborCleanup(float* in, uchar* out, int i, int x, int y, int x_lim, int y_lim)
{
int index;
for (int xx = x - 1; xx < x + 2; ++xx) {
for (int yy = y - 1; yy < y + 2; ++yy) {
if (((xx == x) && (yy==y)) || xx < 0 || yy < 0 || xx >= x_lim || yy >= y_lim)
continue;
index = xx*y_lim + yy;
if ((in[i] == in[index]) && (out[index] == 0))
return 1;
}
}
return 0;
}
void inline neighborCheck(float* in, uchar* out, int i, int x, int y, int x_lim)
{
int indexes[8], cur_index;
indexes[0] = x*x_lim + y;
indexes[1] = x*x_lim + y+1;
indexes[2] = x*x_lim + y+2;
indexes[3] = (x+1)*x_lim + y+2;
indexes[4] = (x + 2)*x_lim + y+2;
indexes[5] = (x + 2)*x_lim + y + 1;
indexes[6] = (x + 2)*x_lim + y;
indexes[7] = (x + 1)*x_lim + y;
cur_index = (x + 1)*x_lim + y+1;
for (int t = 0; t < 8; t++) {
if (in[indexes[t]] < in[cur_index]) {
out[i] = 0;
break;
}
}
if (out[i] == 3)
out[i] = 1;
}
The following listing is a function similar to Matlab's "imregionalmax". It looks for at most nLocMax local maxima above threshold, where the found local maxima are at least minDistBtwLocMax pixels apart. It returns the actual number of local maxima found. Notice that it uses OpenCV's minMaxLoc to find global maxima. It is "opencv-self-contained" except for the (easy to implement) function vdist, which computes the (euclidian) distance between points (r,c) and (row,col).
input is one-channel CV_32F matrix, and locations is nLocMax (rows) by 2 (columns) CV_32S matrix.
int imregionalmax(Mat input, int nLocMax, float threshold, float minDistBtwLocMax, Mat locations)
{
Mat scratch = input.clone();
int nFoundLocMax = 0;
for (int i = 0; i < nLocMax; i++) {
Point location;
double maxVal;
minMaxLoc(scratch, NULL, &maxVal, NULL, &location);
if (maxVal > threshold) {
nFoundLocMax += 1;
int row = location.y;
int col = location.x;
locations.at<int>(i,0) = row;
locations.at<int>(i,1) = col;
int r0 = (row-minDistBtwLocMax > -1 ? row-minDistBtwLocMax : 0);
int r1 = (row+minDistBtwLocMax < scratch.rows ? row+minDistBtwLocMax : scratch.rows-1);
int c0 = (col-minDistBtwLocMax > -1 ? col-minDistBtwLocMax : 0);
int c1 = (col+minDistBtwLocMax < scratch.cols ? col+minDistBtwLocMax : scratch.cols-1);
for (int r = r0; r <= r1; r++) {
for (int c = c0; c <= c1; c++) {
if (vdist(Point2DMake(r, c),Point2DMake(row, col)) <= minDistBtwLocMax) {
scratch.at<float>(r,c) = 0.0;
}
}
}
} else {
break;
}
}
return nFoundLocMax;
}
I do not know if it is what you want, but in my answer to this post, I gave some code to find local maxima (peaks) in a grayscale image (resulting from distance transform).
The approach relies on subtracting the original image from the dilated image and finding the zero pixels).
I hope it helps,
Good luck
I had the same problem some time ago, and the solution was to reimplement the imregionalmax algorithm in OpenCV/Cpp. It is not that complicated, because you can find the C++ source code of the function in the Matlab distribution. (somewhere in toolbox). All you have to do is to read carefully and understand the algorithm described there. Then rewrite it or remove the matlab-specific checks and you'll have it.