I have a bitmap with black background and some random objects in white. How can I identify these separate objects and extract them from the bitmap?
It should be pretty simple to find the connected white pixel coordinates in the image if the pixels are either black or white. Start scanning pixels row by row until you find a white pixel. Keep track of where you found it, create a new data structure to hold its connected object. Do a recursive search from that pixel to its surrounding pixels, add each connected white pixel's coordinates to the data structure. When your search can't find any more connected white pixels "end" that object. Go back to where you started and continue scanning pixels. Each time you find a white pixel see if it is in one of your existing "objects". If not, create a new object and repeat your search, adding connected white pixels as you go. When you are done, you should have a set of data structures representing collections of connected white pixels. These are your objects. If you need to identify what they are or simplify them into shapes, you'll need to do some googling -- I can't help you there. It's been too long since I took that computer vision course.
Feature extraction is a really complex topic and your question didn't expose the issues you face and the nature of the objects you want to extract.
Usually morphological operators help a lot for such problems (reduce noise, fill gaps, ...) I hope you already discovered AForge. Before you reinvent the wheel have a look at it. Shape recognition or blob analysis are buzz works you can have a look at in google to get some ideas for solutions to your problem.
There are several articles on CodeProject that deals with these kinds of image filters. Unfortunately, I have no idea how they work (and if I did, the answer would probably be too long for here ;P ).
1) Morphological operations to make the objects appear "better"
2) Segmentation
3) Classification
Each topic is a big one. There are simple approches but your description is not too detailed...
Related
I have a requirement to scan various images for coloured lines, the result of this determines what we do with an image, no lines = delete, lines = save.
I have been meeting this requirement adequately by simply comparing the colour of each pixel to a list of known colours that we are looking for, if we find above a certain threshold of pixels then we are happy that there is something on the image that we are interested in.
I recently had to re-work this as we started to get highly compressed Jpegs and (for example) the red line ended up being made up of hundreds of shades of red - I got this working reliably but the process got me thinking that there mush be a better way so I have started to look at AForge to determine if it could be used to detect the different coloured lines.
I have spent a day looking into it and think that it will work but need some guidance on what the best approach/method will be as CV is a very big field and I only need to learn a very small part of it for the time being.
This is an example of one of the images
In this instance I'd want to find out about the red and blue lines.
I'd disregard the black ones.
Ive been reading and testing some things with hough line detection and have had some very limited success when detecting a STRAIGHT line on a black and white image but cant find many examples of detecting curved coloured lines.
All Im looking for is a little guidance on whether AForge is the best way forward (if it can even do what I want) and an idea of what the process would look like so that I can go and investigate the right things!
In case this is of use to anyone else in the future I found a way to do this, its still not perfect but has improved the reliability of our process.
Step one -> Remove all but the colour that we are interested in :
var c = Color.Red;
EuclideanColorFiltering filter = new EuclideanColorFiltering();
filter.CenterColor = new RGB(color.R, color.G, color.B);
filter.Radius = (short)radius;
filter.ApplyInPlace(input);
Step 2 -> Convert to gray scale
Grayscale.CommonAlgorithms.BT709.Apply(image);
Step 3 -> Run the result through a Hough
var lineTransform = new HoughLineTransformation();
lineTransform.ProcessImage(input);
HoughLine[] lines =
lineTransform.GetLinesByRelativeIntensity(_intensity);
Step one pretty much yields the same result that I used to get by scanning the image for pixels of a specific colour, but the HoughLineTransform has the effect of identifying which pixels form a line - removing a lot of the noise that we had on the highly compressed JPEGS.
There is still a bit of an issue in that the way that we are filtering out all but the colours that we are interested in doesnt work for all colours, we have quite a few shades of grey that we need to identify by that picks up the outlines of roads etc, so there is still work to do - but what I describe above has got us much closer to a solution.
I am writing some software that periodically checks a camera image to identify whether an object has been introduced to the viewed scene. I am using ImageMagick in my WinForms software to compare two images to create a third. In the third image, a pixel is white if the first two images had a similar-coloured pixel, and black if they were different. So if the user sees a group of black pixels, they will know something has been placed in the scene that wasn't there previously, as seen here:
The user will not be seeing this image, so I would like my software to identify this for me. I don't need anything too complex from this analysis - just a Boolean for whether something was changed in the scene.
In my mind, there are two approaches to analysing this; counting the number of black pixels in the image, or I could write some algorithm to identify patches of black. My question is about the second approach, since it feels like the more correct approach. The image is a bit too noisy (you can see false positives on straight edges) for me to feel entirely comfortable with counting.
To identify a group, I have considered using some for loops to look at the colours of pixels surrounding every pixel but this seems like it would take forever. My processing time can't take more than a few seconds so I need to be wary of this. Are there cleaner or more-efficient ways to identify groups of similarly-coloured pixels? Or will I need to run loops and be as efficient as possible?
Threshold the image such that black pixels will have value 1 non black will have zero.
Use connected component labeling to find all the groups of connected black pixels. http://www.imagemagick.org/script/connected-components.php
Filter out the components that are too small or doesn't have the correct shape(for example you can have a long line on the sides so they have a lot of black pixels but you are not expecting to see a long line as a valid group of black pixels)
At this point I assume you have a sense of the scale of the objects that you are interested in capturing. For example, if you did have an entirely non-black screen (let's ignore noise for the purpose of this discussion), except you have a black pixel object that is only roughly 10 pixels in diameter. This seems to be frightfully small, and not enough information to be useful.
Once you have determined what is the minimum size of black mass you are willing to accept, I would then go about querying a staggered matrix.
i.e., a pattern like:
Use a little math to determine what acceptable noise is.
Once you have positive results, (pixels = black), investigate in those sectors.
I'm working on an OCR program for one of my classes and I'm trying to find circular closed regions in the text to classify characters. Words have already been skeletonized. For example, in this image:
http://i.imgur.com/VLHJp.jpg
I'd like to find the location of the circular O or even the half circle in the E. I've attempted to convert the pixels into an array and then loop through all the white pixels, finding closed paths but this didn't work. I might not have implemented this correctly however. Any other solutions? Thanks in advance.
Edit:
Unfortunately I cannot use Tesseract or other OCR programs because I have to develop my own for my college class. I've used the AForge library to do many tasks such as the skeletonization and wanted to use the circle detection or shape detection classes there but these shapes are too obtuse to work with that.
One of the ways to find closed areas is to use flood fill algorithms. Assuming a pixel at the edge of the image (e.g. 0,0) can't be in a closed in area start from there and flood out. Then you can eliminate all pixels in that flood.
Work through the other pixels in the image (that aren't part of your set of bounding pixels) and do floods. These floods are 'enclosed', you could eliminate them if they reach the edge of the image if you want to. Each flood should take in a reasonable number of pixels so this algorithm eliminates pixels pretty quickly.
In your case I'd suggest you need to set a minimum area (pixel count) to exclude noise.
I have an image that is a depth heatmap that I've filtered out anything further away than the first 25% of the image.
It looks something like this:
There are two blobs of color in the image, one is my hand (with part of my face behind it), and the other is the desk in the lower left corner. How can I search the image to find these blobs? I would like to be able to draw a rectangle around them if possible.
I can also do this (ignore shades, and filter to black or white):
Pick a random pixel as a seed pixel. This becomes area A. Repeatedly expand A until A doesn't get any bigger. That's your area.
The way to expand A is by looking for neighbor pixels to A, such that they have similar color to at least one neighboring pixel in A.
What "similar color" means to you is somewhat variable. If you can make exactly two colors, as you say in another answer, then "similar" is "equal". Otherwise, "similar" would mean colors that have RGB values or whatnot where each component of the two colors is within a small amount of each other (i.e. 255, 128, 128 is similar to 252, 125, 130).
You can also limit the selected pixels so they must be similar to the seed pixel, but that works better when a human is picking the seed. (I believe this is what is done in Photoshop, for example.)
This can be better than edge detection because you can deal with gradients without filtering them out of existence, and you don't need to process the resulting detected edges into a coherent area. It has the disadvantage that a gradient can go all the way from black to white and it'll register as the same area, but that may be what you want. Also, you have to be careful with the implementation or else it will be too slow.
It might be overkill for what you need, but there's a great wrapper for C# for the OpenCV libraries.
I have successfully used OpenCV in C++ for blob detection, so you might find it useful for what you're trying to do.
http://www.emgu.com/wiki/index.php/Main_Page
and the wiki page on OpenCV:
http://en.wikipedia.org/wiki/OpenCV
Edited to add: Here is a blobs detection library for Emgu in C#. There is even some nice features of ordering the blobs by descending area (useful for filtering out noise).
http://www.emgu.com/forum/viewtopic.php?f=3&t=205
Edit Again:
If Emgu is too heavyweight, Aforge.NET also includes some blob detection methods
http://www.aforgenet.com/framework/
If the image really is only two or more distinct colours (very little blur between colours), it is an easy case for an edge detection algorithm.
You can use something like the code sample from this question : find a color in an image in c#
It will help you find the x/y of specific colors in your image. Then you could use the min x/max x and the min y/max y to draw your rectangles.
Detect object from image based on object color by C#.
To detect a object based on its color, there is an easy algorithm for that. you have to choose a filtering method. Steps normally are:
Take the image
Apply ur filtering
Apply greyscalling
Subtract background and get your objects
Find position of all objects
Mark the objects
First you have to choose a filtering method, there are many filtering method provided for C#. Mainly I prefer AForge filters, for this purpose they have few filter:
ColorFiltering
ChannelFiltering
HSLFiltering
YCbCrFiltering
EuclideanColorFiltering
My favorite is EuclideanColorFiltering. It is easy and simple. For information about other filters you can visit link below. You have to download AForge dll for apply these in your code.
More information about the exact steps can be found here: Link
We're currently creating a simple application for image manipulation in Silverlight, and we've hit a bit of a snag. We want users to be able to select an area of an image (either by drawing a freehand line around their chosen area or by creating a polygon around it), and then be able to apply effects to the pixels within that selection.
Creating a selection of images is easy enough, but we want a really fast algorithm for deciding which pixels should be manipulated (ie. something to detect which pixels are within the user's selection).
We've thought of three possibilities so far, but we're sure that there must be a really efficient and quick way of doing this that's better than these.
1. Pixel by pixel.
We just go through every pixel in an image and check whether it's within the user selection. Obviously this is far too slow!
2. Using a Line Crossing Algorithim.
The type of thing seen here.
3. Flood Fill.
Select the pixels along the path of the selection and then perform a flood fill within that selection. This might work fine.
This must a problem that's commonly solved, so we're guessing there's a ton more solutions that we've not even thought of.
What would you recommend?
Flood fill algorithm is a good choice.
Take a look at this implementation:
Queue-Linear Flood Fill: A Fast Flood Fill Algorithm
You should be able to use your polygon to create a clipping path. The mini-language for describing polygons for Silverlight is quiet well documented.
Alter the pixels on a copy of your image (all pixels is usually easy to modify than some pixels), then use the clipping path to render only the desired area of the changes back to the original image (probably using an extra buffer bitmap for the result).
Hope this helps. Just throwing the ideas out and see if any stick :)