Area segmentation within a segmented area - java

Here's an image:
I would like to know how i can set the black circle to white and the rest to black.
(So segment the black circle within the white area).
I know i can invert the image and the circle will be white ... but so will the entire black part that is seen in this image.
If i would have to do this in matlab i would do a connected component operation and check the circularity of the BLOBs. Though I have to do this in opencv (javacv to be precise.)
Is there an easy way of doing this in opencv (javacv).
Thx in advance

There is a simple way in OpenCV using findContours() and drawContours(). If you use the hierarchical version of findContours(), you can then look through the hierarchy and draw (fill) the child contour of the white quad only. This has the additional advantage that you can do some sanity checks (e.g. checking the size of the contour to see if it is approximately the size you expect) if necessary. I don't know anything about java or javacv, but maybe you can check out the c++ example for findcontours included with opencv for inspiration?

You can detect image objects on images by using openCV library(through java adapter); for it you will need to train network for circles.
Regarding exactly your case(probably this solution will not be generic) you can split your image on segments, and using as condition - color changing, see pseudo code below:
//build color switching list
List<Point> colorSwitches = ...
for(each horizontal line from image){
for(each pixel from line){
if(color of previous pixel != color of current pixel){
colorSwitches.add(currentPoint)
}
}
}
// so, you have detected margins of your image objects; now we need to merge neighbor pixels into image objects, where image object is collection of margin points(you should create this class)
List<ImageObject> imageObjects = ...
for(each color switch){
if(current pixel is connected with pixels from existing image objects){
// returns image object neared with current point
getRelatedImageObject(imageObjects).add(currentPoint);
}else{
imageObjects.add(new ImageObject(currentPixel));
}
}
// now we have list of objects from image, and we need to match objects
Ok, its general lines how to do what you need, if you will need more exactly I will try to explain more detailed. Also you can contact me directly
Hope it will help you.

Related

What does virtual display in Android do with Image pixels when smaller display dimensions are set than grabbed one?

I dont understand what happens with pixels in Virtual Display in Android when output dimensions are reduced compared to the input ones ?
When I have for example input = size of my Display = 1920x960 and I set outputs to be 1920/3 and 960/3, what happens in that case with image pixels:
pixel density is increased or
maybe it takes only smaller part of screen that is centered and has dimensions 640x320 or
something else?
Additionally, is there a way that I can only grab center part of screen as in picture below?
By digging in the AOSP, watching, looking at a thread and experimenting~
I have come to my own (might be overly) simplified conclusion.
Android calls the native Java SDK which produces the information that's needed to render a bitmap/pixels on a Java program.
If the results are the same don't need to pass/copy it again to the GPU.
If the results are not the same pass/copy it to the GPU to be "invalidated" then re-rendered.
Now to your question.
By looking at the Bitmap class and looking at this thread It came to my mind that resizing depends on the scaling ratio passed on to the Matrix class.
If resized, it will expensively create a new Bitmap that looks like something either a pretty-bad higher pixel-density or not-so-smooth lower pixel density.
If the pixel-density is increased (smaller dimensions, your case) it will look squashed and if need be, the colors are averaged to the nearest neighbouring pixels. ("kind of" like how JPEG works).
After resizing it will still stay to it's origin (top-left part of the rendered object) which is defined by it's X and Y coordinates.
For your second question, about screen grabbing you can take a look at this and then programatically resize the image by doing something like this:
//...
Bitmap.createBitmap(screenshot_bitmap, left, top, right, bottom);
//...

opencv java - detect all the rectangles and fill them with an image

I am currently working on a solution for an automatic image edit.
And I have used Canny Edge Detection and Closing.
But What I ultimately want to accomplish is to find all the rectangles from blueprint and fill them with an image what I have.
I want to know the process that I need to take, not the exact code or solution!
Please suggest me what steps should I take to accomplish it, thx.
Image that has the rectangles
Image that needs to go into all the rectangles
what i have done so far
2018-02-12 EDITTED(clean rectangle detected)
// I have done finding the rectangles and drawing lines over them, but the result is not really reliable than I expected(it draws line on rectangles those are not a parking space), and I do not know how to put an image on those rectangle instead of drawing line on them. please help me out!
P.S : Only in JAVA please !
In your case, you don't need Canny. Your image is really clean and edges are really visible already. A simple Threshold, will work better.
For rectangle detection take a look at this example (included with opencv) that uses findcontours and checks the angles: https://github.com/opencv/opencv/blob/master/samples/cpp/squares.cpp
In your case, you can skip the Canny step because you don't have gradients. You may need to modify the filtering, like side dimensions for your case.
Once the rectangles look good, you just need to copy your image in the location. If rectangles are rotated, you will have to rotate your image as well.
EDIT:
To copy the small image onto the big image you can do the following
Mat submatImg = bigImage.submat(new Rect(x, y, smallImage.width(), smallImage.height());
smallImage.copyTo(submatImg);
If you need to do resizing and rotations, take a look at geometric transformations

find archery target in image of different perspectives

I'm trying to find a way to identify an archery target and all of its rings on a photo which might be made of different perspectives:
My goal is to identify the target and later on also where the arrows hit the target to automatically count their score. Presumptions are as follows:
The camera's position is not fixed and might change
The archery target might also move or rotate slightly
The target might be of different size and have different amount of circles
There might be many holes (sometimes big scratches) in the target
I have already tried OpenCV to find contours, but even with preprocessing (grayscale -> blur (-> threshold) -> edge detection) I still find a few houndred contours which are all distracted by the arrows or other obstacles (holes) on the target, so it is impossible to find a nice circular line. Using Hough to find circles doesn't work either as it will give me weired results as Hough will only find perfect circles and not ellipses.
With preprocessing the image this is my best result so far:
I was thinking about ellipse and circle fitting, but as I don't know radius, position and pose of the target this might be a very cpu consuming task. Another thought was about using recognition from a template, but the position and rotation of the target changes often.
Now I have the idea to follow every line on the image to check if it is a curve and then guess which curves belong together to form a circle/ellipse (ellipse because of the perspective). The problem is that the lines might be intersected by arrows or holes in a short distance so the line would be too short to check if it is a curve. With the smaller circles on the target the chance is high that it isn't recognised at all. Also, as you can see, circle 8, 7 and 6 have no clear line on the left side.
I think it is not neccessary to do perspective correction to achieve this task as long as I can clearly identify all the rings in the target.
I googled a long time and found some thesis which are all not exactly focussed on this specific task and also too mathematical for me to understand.
Is it by any chance possible to achieve this task? Could you share with me an idea how to solve this problem? Anything is very appreciated.
I'm doing this in Java, but the programming language is secondary. Please let me know if you need more details.
for starters see
Detecting circles and shots from paper target.
If you are using standardized target as on the image ( btw. I use these same too for my bow :) ) then do not cut off the color. You can select the regions of blue red and yellow pixels to ease up the detection. see:
footprint fitting
From that you need to fit the circles. But as you got perspective then the objects are not circles nor ellipses. You got 2 options:
Perspective correction
Use right bottom table rectangle area as marker (or the whole target). It is rectangle with known aspect ratio. so measure it on image and construct transformation that will change the image so it became rectangle again. There are tons of stuff about this: 3D scene reconstruction so google/read/implement. The basic are based just on De-skew + scaling.
Approximate circles by ellipses (not axis aligned!)
so fit ellipses to found edges instead circles. This will not be as precise but still close enough. see:
ellipse fitting
[Edit1] sorry did not have time/mood for this for a while
As you were unable to adapt my approach yourself here it is:
remove noise
you need to recolor your image to remove noise to ease up the rest... I convert it to HSV and detect your 4 colors (circles+paper) by simple tresholding and recolor the image to 4 colors (circles,paper,background) back into RGB space.
fill the gaps
in some temp image I fill the gaps in circles created by arrows and stuff. It is simple just scan pixels from opposite sides of image (in each line/row) and stop if hit selected circle color (you need to go from outer circles to inner not to overwrite the previous ones...). Now just fill the space between these two points with your selected circle color. (I start with paper, then blue,red and yellow last):
now you can use the linked approach
So find avg point of each color, that is approx circle center. Then do a histogram of radius-es and chose the biggest one. From here just cast lines out of the circle and find where the circle really stops and compute the ellipse semi-axises from it and also update the center (that handles the perspective distortions). To visually check I render cross and circle for each circle into the image from #1:
As you can see it is pretty close. If you need even better match then cast more lines (not just 90 degree H,V lines) to obtain more points and compute ellipse algebraically or fit it by approximation (second link)
C++ code (for explanations look into first link):
picture pic0,pic1,pic2;
// pic0 - source
// pic1 - output
// pic2 - temp
DWORD c0;
int x,y,i,j,n,m,r,*hist;
int x0,y0,rx,ry; // ellipse
const int colors[4]=// color sequence from center
{
0x00FFFF00, // RGB yelow
0x00FF0000, // RGB red
0x000080FF, // RGB blue
0x00FFFFFF, // RGB White
};
// init output as source image and resize temp to same size
pic1=pic0;
pic2=pic0; pic2.clear(0);
// recolor image (in HSV space -> RGB) to avoid noise and select target pixels
pic1.rgb2hsv();
for (y=0;y<pic1.ys;y++)
for (x=0;x<pic1.xs;x++)
{
color c;
int h,s,v;
c=pic1.p[y][x];
h=c.db[picture::_h];
s=c.db[picture::_s];
v=c.db[picture::_v];
if (v>100) // bright enough pixels?
{
i=25; // treshold
if (abs(h- 40)+abs(s-225)<i) c.dd=colors[0]; // RGB yelow
else if (abs(h-250)+abs(s-165)<i) c.dd=colors[1]; // RGB red
else if (abs(h-145)+abs(s-215)<i) c.dd=colors[2]; // RGB blue
else if (abs(h-145)+abs(s- 10)<i) c.dd=colors[3]; // RGB white
else c.dd=0x00000000; // RGB black means unselected pixels
} else c.dd=0x00000000; // RGB black
pic1.p[y][x]=c;
}
pic1.save("out0.png");
// fit ellipses:
pic1.bmp->Canvas->Pen->Width=3;
pic1.bmp->Canvas->Pen->Color=0x0000FF00;
pic1.bmp->Canvas->Brush->Style=bsClear;
m=(pic1.xs+pic1.ys)*2;
hist=new int[m]; if (hist==NULL) return;
for (j=3;j>=0;j--)
{
// select color per pass
c0=colors[j];
// fill the gaps with H,V lines into temp pic2
for (y=0;y<pic1.ys;y++)
{
for (x= 0;(x<pic1.xs)&&(pic1.p[y][x].dd!=c0);x++); x0=x;
for (x=pic1.xs-1;(x> x0)&&(pic1.p[y][x].dd!=c0);x--);
for (;x0<x;x0++) pic2.p[y][x0].dd=c0;
}
for (x=0;x<pic1.xs;x++)
{
for (y= 0;(y<pic1.ys)&&(pic1.p[y][x].dd!=c0);y++); y0=y;
for (y=pic1.ys-1;(y> y0)&&(pic1.p[y][x].dd!=c0);y--);
for (;y0<y;y0++) pic2.p[y0][x].dd=c0;
}
if (j==3) continue; // do not continue for border
// avg point (possible center)
x0=0; y0=0; n=0;
for (y=0;y<pic2.ys;y++)
for (x=0;x<pic2.xs;x++)
if (pic2.p[y][x].dd==c0)
{ x0+=x; y0+=y; n++; }
if (!n) continue; // no points found
x0/=n; y0/=n; // center
// histogram of radius
for (i=0;i<m;i++) hist[i]=0;
n=0;
for (y=0;y<pic2.ys;y++)
for (x=0;x<pic2.xs;x++)
if (pic2.p[y][x].dd==c0)
{
r=sqrt(((x-x0)*(x-x0))+((y-y0)*(y-y0))); n++;
hist[r]++;
}
// select most occurent radius (biggest)
for (r=0,i=0;i<m;i++)
if (hist[r]<hist[i])
r=i;
// cast lines from possible center to find edges (and recompute rx,ry)
for (x=x0-r,y=y0;(x>= 0)&&(pic2.p[y][x].dd==c0);x--); rx=x; // scan left
for (x=x0+r,y=y0;(x<pic2.xs)&&(pic2.p[y][x].dd==c0);x++); // scan right
x0=(rx+x)>>1; rx=(x-rx)>>1;
for (x=x0,y=y0-r;(y>= 0)&&(pic2.p[y][x].dd==c0);y--); ry=y; // scan up
for (x=x0,y=y0+r;(y<pic2.ys)&&(pic2.p[y][x].dd==c0);y++); // scan down
y0=(ry+y)>>1; ry=(y-ry)>>1;
i=10;
pic1.bmp->Canvas->MoveTo(x0-i,y0);
pic1.bmp->Canvas->LineTo(x0+i,y0);
pic1.bmp->Canvas->MoveTo(x0,y0-i);
pic1.bmp->Canvas->LineTo(x0,y0+i);
//rx=r; ry=r;
pic1.bmp->Canvas->Ellipse(x0-rx,y0-ry,x0+rx,y0+ry);
}
pic2.save("out1.png");
pic1.save("out2.png");
pic1.bmp->Canvas->Pen->Width=1;
pic1.bmp->Canvas->Brush->Style=bsSolid;
delete[] hist;

Get portion of an image using rotated Shape

From the above image if I want a portion behind the RED Rectangle I can easily get it,
but the issue I cannot get the portion behind the Yellow Rectangle because it is rotated.
So how can I get a portion of an image from a rotated shape on it?
For example my goal is to get a portion of an Image where the rectangle is located on the image. if someone rotates this rectangle by an x degree [in whatever direction] then it is getting difficult to extract the exact portion of an image after applying rotation.
Any suggestions?
Here a more lengthy description of a possible approach. I do not know the Java2D drawing API very well but if I remember correctly it has the capabilities to do what is required.
First you have to figure out the translation and rotation of the subregion you want compared to an equally size rectangle located straight in the upper left corner in the image. Then invert this transformation.
Make a graphics context which is backed by a bitmap in memory. This one should have the size of the subimage you want. Setup the inverse transformation you calculated earlier on the context and draw your image at position 0,0. As Java2D will take the transformation into account you should now get the sub image you want in the memory bitmap.
Mihir, I think you might be getting distracted by the rotation/AffineTransform aspects of this challenge and it is leading you down the wrong road. Also keep in mind that I don't totally know what you mean by "get" here -- do you want to save out the highlighted region to an image? Do you want to render it as a watermark on another image? etc... I'll just try and answer in the general case to get you down the right track.
What you want is the content from the image defined by the polygon in yellow in your image above; ignoring the fact that it looks like a rotated rectangle.
It is late and I am missing a step in here, but I think this will get you 90% of the way there and clarify the last piece (Graphics2D.setClip) that you need.
Create a java.awt.Polygon that defines the region around the area you want.
Use getBounds() or getBounds2D() to get the width/height of the bounding box required to hold this Polygon when rendered out into a rectangle. (e.g. boundingBox)
Create a new BufferedImage with these width/height values.
Get the Graphics2D from the new BufferedImage (e.g. newG2)
newG2.drawImage(originalImage, boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height)
NOTE This is where my memory is failing me; at some point you need to set the clip on newG2 (newG2.setClip(someShape)) so when the bounding box is rendered into it, you don't get the full bounding box of graphics rendered in, but instead some subset as defined by the yellow outline.
One easy way to do this is to create two Polygon's:
poly1 = a java.awt.Polygon that defines the yellow selection in the ORIGINAL image.
poly2 = a java.awt.Polygon that defines the exact same shape of Polygon, but shifted to a 0,0 origin point.
poly1 is used to get the bounding box to copy out the full bounding box that encompasses the content selected in yellow (and extra content around it)
poly2 is used to set the clip on the target Graphics2D (newG2) so when the bounding box is rendered into it, we clip back out everything outside of that Yellow shape so we just get the content in Yellow. You'll likely want to use an ARGB image type and set the background of the target image as transparent otherwise you'll get a black fill color.
I think this is the right direction for the clips; I was up to my eyeballs in Java2D for years and years but have been out of it for a while and forget if this will give you exactly what you want or not; you might need to tweak it around, but these are all the tools you need.

Dividing the image and getting coordinates

I have an image with yellow background containing a random figure as shown in figure:
The random figure is divided by black lines into image pieces. Now each piece can be represented separately as a square containing that piece image with transparent background.
My question if it possible to find the coordinates of each piece algorithmically in the original image?
I am writing this application in Java.
I don't have much idea about the graphics. If its possible then please elaborate little bit.
Presuming the images look mostly like what you have here
Loop
Find a Red pixel
If found
flood fill red to non-red at this point, remembering region
create output image from this region
else
You are done
Use connected component labeling on the binary image (threshold your current image).
I used MATLAB to threshold the image, and run a labeling algorithm. Then I used region properties to find the centroid of each connected component (which are the image pieces you need). The following is the labeled image with the black stars representing the centroid of each piece:

Categories

Resources