How to Draw BoundingBox or Tag Objects Which Has Less Area Than Others - image

In my image I have 5 Objects in black-white form. Some are respectively small, some are bigger.
So what i am trying to do is drawing a BoundingBox or tag the objects which has less area than others (ex. under 10pixels/area) .
I couldn't make this happen, can anyone help?

That's two separate problems. The first is to select only objects above a certain area. So simply remove all objects below it:
clean = bwareaopen (im, 10); # remove all objects with area below 10
Then for the second problem there are many possibilities. You can get their borders:
borders = bwperim (clean);
imshow (borders);
You can label them:
labeled = bwlabel (clean);
imshow (labeled);
Or you can get their bounding box (which depending on the shape of your objects may overlap):
props = regionprops (clean, 'BoundingBox');
all_bb = props.BoundingBox;
boxes = false (size (clean));
for i = 1:numel (all_bb)
bb = all_bb{i};
bb(round (bb(2):bb(2)+bb(4), bb(1):bb(1)+bb(3))) = true;
end
imshow (boxes);
Note: this was written out of my head, no testing. There may be small oversights, but nothing major.

Related

Is there a simple way of handling (transforming) a group of objects in SkiaSharp?

In a nutshell, let's say, I need to draw a complex object (arrow) which consists of certain amount of objects, like five (or more) lines, for instance. And what's more important, that object must be transformed with particular (dynamic) coordinates (including scaling, possibly).
My question is whether SkiaSharp has anything which I can use for manipulating of this complex object transformation (some sort of grouping etc.) or do I still need to calculate every single point manually (with matrix, for instance).
This question is related particularly to SkiaSharp as I use it on Xamarin, but maybe some general answers from Skia can also help with it?
I think, the question might be too common (and possibly not for stackoverflow exactly), but I just can't find any specific information in google.
Yes, I know how to use SkiaSharp for drawing primitives.
create an SKPath and add lines and other shapes to it
SKPath path = new SKPath();
path.LineTo(...);
...
...
then draw the SKPath on your canvas
canvas.DrawPath(path,paint);
you can apply a transform to the entire path before drawing
var rot = new SKMatrix();
SKMatrix.RotateDegrees(ref rot, 45.0f);
path.Transform(rot);
If you are drawing something more complex than a path SKPicture is perfect for this. You can set it up so that you construct it once and then reuse it easily and efficiently. In the example below, the SKPicture's origin is in the center of a 100 x 100 rectangle but that is arbitrary.
SKPicture myPicture;
SKPicture MyPicture {
get {
if(myPicture != null) {
return myPicture;
}
using(SKPictureRecorder recorder = new SKPictureRecorder())
using(SKCanvas canvas = recorder.BeginRecording(new SKRect(-50, -50, 50, 50)))
// draw using primitives
...
myPicture = recorder.EndRecording();
}
return myPicture;
}
}
Then you apply your transforms to the canvas, draw the picture and restore the canvas state. offsetX and offsetY correspond to where the origin of the SKPicture will be rendered.
canvas.Save();
canvas.Translate(offsetX, offsetY);
canvas.Scale(scaleAmount);
canvas.RotateDegrees(degrees);
canvas.DrawPicture(MyPicture);
canvas.Restore();

PIL: Imageobject.save() after drawing completely corrupts images and smurfs the ouput

I have these two functions in my program:
def depict_ph_increase(x,y,color, imobject):
program_print(color)
draw = PIL.ImageDraw.Draw(imobject)
draw.text((x, y),color,(255,255,255))
imobject.save('tmp-out.gif')
im_temp = PIL.Image.open("tmp-out.gif")#.convert2byte()
im_temp = im_temp.resize((930, 340), PIL.Image.ANTIALIAS)
MAP_temp = ImageTk.PhotoImage(im_temp)
map_display_temp = Label(main, image=MAP_temp)
map_display_temp.image = MAP_temp # keep a reference!
map_display_temp.grid(row=4,column=2, columnspan=3)
def read_temp_pixels(temperature_file, rngup, rngdown):
temp_image_object = PIL.Image.open(temperature_file)
(length, width) = get_image_size(temp_image_object)
(rngxleft, rngxright) = rngup
(rngyup,rngydown) = rngdown
print 'the length and width is'
print length, width
hotspots = 5;
for hotspot in range(0,hotspots):
color = "#ffffff"
while color == "#ffffff" or color == "#000000" or color == "#505050" or color == "#969696":
yc = random.randint(rngxleft, rngxright)
xc = random.randint(rngyup,rngydown)
color = convert_RGB_HEX(get_pixel_color(temp_image_object, xc, yc))
depict_ph_increase(xc,yc,color, temp_image_object)
The bottom one calls the top one. Their job is to read in this image:
It then randomly selects a few pixels, grabs their colors, and writes the hex values of the colors on top. But, when it redisplays the image, it gives me this garbage:
Those white numbers up near the upper right corner are the hex values its drawing. Its somehow reading the values from the corrupted image, despite the fact that I don't collect the values until AFTER I actually call the ImageDraw() method. Can someone explain to me why it is corrupting the image?
Some background--the get_pixel_color() function is used several other times in the program and is highly accurate, its just reading the pixel data from the newly corrupted image somehow. Furthermore, I do similar image reading (but not writing) at other points in my code.
If there is anything I can clarify, or any other part of my code you want to see, please let me know. You can also view the program in its entirety at my github here: https://github.com/jrfarah/coral/blob/master/src/realtime.py It should be commit #29.
Other SO questions I have examined, to no avail: Corrupted image is being saved with PIL
Any help would be greatly appreciated!
I fixed the problem by editing this line:
temp_image_object = PIL.Image.open(temperature_file)
to be
temp_image_object = PIL.Image.open(temperature_file).convert('RGB')

Performance problems with scenekit

I've got a row dimensional array of values that I want to visualize in 3D and I'm using scene kit under OS X for it. I've done it in a clumsy manner by using each column as a point on the X axis, each row as a point on the Z axis, and each value as a normalized point on the Y axis -- I place a sphere at the vector defined by each data point. It works but it doesn't look too good.
I've also done this by building a mesh of lines based on #Matthew's function in Drawing a line between two points using SceneKit (the answer he posted, not the original question). For each point I use his function to draw two lines - one between my current point and the next point to the right and another between my current point and the next point towards the front (except when there is no additional column/row, of course).
Using the second method, my results look much better... however the performance is quite hideous! It takes quite a long time to complete the initial rendering, and if I use a trackpad/mouse to rotate or translate the scene, I might as well get a cup of coffee to wait until my system is usable again (and this is not much hyperbole). Using the sphere method, things render and update very quickly.
Any advice on how to improve the performance when using the lines method? (Note that I am not trying to add both lines and spheres at the same time.) Code-wise, the only difference between approach is which of the following methods gets called (and that for each point, addPixelAt... is called once, but addLineAt... is called twice for most points).
- (SCNNode *)addPixelAtRow:(CGFloat)row Column:(CGFloat)column size:(CGFloat)size color:(NSColor *)color
{
CGFloat radius = 0.5;
SCNSphere *ball = [SCNSphere sphereWithRadius:radius*1.5];
SCNMaterial *material = [SCNMaterial material];
[[material diffuse] setContents:color];
[[material specular] setContents:color];
[ball setMaterials:#[material]];
SCNNode *ballNode = [SCNNode nodeWithGeometry:ball];
[ballNode setPosition:SCNVector3Make(column, size, row)];
[_baseNode addChildNode:ballNode];
return ballNode;
}
- (SCNNode *)addLineFromRow:(CGFloat)row1 Column:(CGFloat)column1 size:(CGFloat)size1
toRow2:(CGFloat)row2 Column2:(CGFloat)column2 size2:(CGFloat)size2 color:(NSColor *)color
{
SCNVector3 positions[] = {
SCNVector3Make(column1, size1, row1),
SCNVector3Make(column2, size2, row2)
};
int indices[] = {0, 1};
SCNGeometrySource *vertexSource = [SCNGeometrySource geometrySourceWithVertices:positions count:2];
NSData *indexData = [NSData dataWithBytes:indices length:sizeof(indices)];
SCNGeometryElement *element = [SCNGeometryElement geometryElementWithData:indexData
primitiveType:SCNGeometryPrimitiveTypeLine
primitiveCount:1
bytesPerIndex:sizeof(int)];
SCNGeometry *line = [SCNGeometry geometryWithSources:#[vertexSource] elements:#[element]];
SCNMaterial *material = [SCNMaterial material];
[[material diffuse] setContents:color];
[[material specular] setContents:color];
[line setMaterials:#[material]];
SCNNode *lineNode = [SCNNode nodeWithGeometry:line];
[_baseNode addChildNode:lineNode];
return lineNode;
}
From the data that you've shown in your question I would say that your main problem is the number of draw calls. Your's is in the tens of thousands, which is way too much. It should probably be a lot closer to ~100.
The reason why you have so many draw calls is that you have so many distinct objects in your scene (each line). The better (but more advanced solution) would probably be to generate a single element for the entire mesh that consists of all the lines. If you want to achieve the same rendering with that mesh (with a color from cold to warm based on the height) then you could do that in a shader modifier.
However, in your case I would start by flattening all the lines (since that would be the smallest code change and should still have a significant performance improvement in your case).
(Optimizing performance is always an iterative process. Once you fix one thing there will be another thing which is the most expensive operation. Without your code I can only say what would help with the current performance problem)
Create an empty node (without adding it to your scene) and generate all the lines, adding them to this node. Then create a flattened copy of that node by calling flattenedClone on the node that contains all the lines
SCNNode *nodeWithAllTheLines = [SCNNode node];
// create all the lines and add them to it...
SCNNode *flattenedNode = [nodeWithAllTheLines flattenedClone];
[_baseNode addChildNode:flattenedNode];
When you do this you should see a significant drop in the number of draw calls (the number after the diamond in the statistics) and hopefully a big increase in performance.

segment object(leaf) which is on the white paper using image processing

I want to get only leaf from an image.
The background is a normal white paper(A4) and there is some shadow.
I apply some method (structure element,edge detection using filter) but I cannot find the general way which can apply all the image.
these are examples.
Are there better methods for this problem??
thank you
another example.
and the result I got is
By using
hsv_I = rgb2hsv(I);
Is = hsv_I(:,:,2);
Is_d = imdilate(Is,strel('diamond',4));
Is_e = imerode(Is,strel('diamond',2));
Is_de = imerode(Is_d,strel('disk',2));
Is_def = imfill(Is_de,'holes');
Is_defe = imerode(Is_def,strel('disk',5));
Then Is_defe is a mask to segment
But the method that i did is very specific. I cannot use this in general.
If you have the Image Processing Toolbox, you could do as follows:
The code below first estimates the threshold with the function graythresh, thresholds the image and fills holes with the imfill function. Suppose I is a cell containing your RGB images:
for k=1:length(I)
t=graythresh(rgb2gray(I{k}));
BW{k}=imfill(~im2bw(I{k}, t), 'holes');
subplot(length(I),1,k), imshow(BW{k});
end

matlab: texture classification

I have a histology image like this:
From the image, we can observe there are two kinds of different cells.
and
Is there any way that I can separate these two types of cells into two groups?
How about using your raw image and previous code to achieve this?
% % % your old code
I=imread(file);
t1=graythresh(I);
k1=im2bw(I,t1);
k1=~k1;
se = strel('disk',1);
k0=imfill(~k1,'holes');
cc = conncomp(k0);
k0(cc.PixelIdxList{1})=0;
k1=imfill(k1,'holes');
mask=k0 | k1;
%%%%%%%%%%%%%%%%%%
This will give you:
I=rgb2hsv(I);
I=double(I);
I1=I(:,:,1); % again, the channel that can maximizing the margin between donut and full circle
Imask=(I1-0.2).*(I1-0.9)<0;
k2=mask-Imask;
k2=bwareaopen(k2,100);
This will give you:
k2=mask-Imask;
I2=zeros(size(I1,1),size(I1,2),3);
I2(:,:,1)=(k2==1)*255;
I2(:,:,3)=((I1-0.2).*(I1-0.9)<0)*255;
imshow(I2)
will finally give you (the two types are stored in two channels in the rgb image):
I would use regionprops
props=regionprops(YourBinaryImage, 'Solidity');
The objects with a high solidity will be the disks, those with a lower solidity will be the circles.
(Edit) More formally:
I=imread('yourimage.jpg');
Bw=~im2bw(I, 0.5);
BWnobord = imclearborder(Bw, 4); % clears the partial objects
Props=regionprops(BWnobord, 'All');
solidity=cell2mat({Props.Solidity});
Images={Props.Image};
Access the elements of Images where the value in solidity is higher than 0.9 and you get your disks. The circles are the other ones.
Hope it helps

Resources