Python: Crop out area from image along borders - python

What functions (and how I should use them) should I use to crop out the center part of this image? I want to take just the less-dense parts, not the dense borders.
Thanks!
In the end, I want to either count the tiny circles/dots (cells) in the areas or calculate the area of the less-dense parts, outlined in the second image. I've done this before with ImageJ by tracing out the area by hand, but it is a really tedious process with lots of images.
Original
Area traced
I've currently looked at Scipy, but they are big and I don't really know how to approach this. If someone would point me in the right direction, that would be great!

It would take me a bit longer to do in Python, but I tried a few ideas just on the command-line with ImageMagick which is installed on most Linux distros and is available for free for macOS and Windows.
First, I trimmed your image to get rid of extraneous junk:
Then, the steps I did were:
discard the alpha/transparency channel
convert to greyscale as there is no useful colour information,
normalised to stretch contrast and make all pixels in range 0-255,
thresholded to find cells
replaced each pixel by the mean of their surrounding 49x49 pixels (box blur)
thresholded again at 90%
That command looks like this in Terminal/Command Prompt:
convert blobs.png -alpha off -colorspace gray -normalize -threshold 50% -statistic mean 49x49 -threshold 90% result.png
The result is:
If that approach looks promising for your other pictures we can work out a Python version pretty quickly, so let me know.
Of course, if you know other useful information about your image that could help improve things... maybe you know the density is always higher at the edges, for example.
In case anyone wants to see the intermediate steps, here is the image after grey scaling and normalising:
And here it is after blurring:

Related

Skewing text - How to take advantage of existing edges

I have the following JPG image. If I want to find the edges where the white page meets the black background. So I can rotate the contents a few degrees clockwise. My aim is to straighten the text for using with Tesseract OCR conversion. I don't see the need to rotate the text blocks as I have seen in similar examples.
In the docs Canny Edge Detection the third arg 200 eg edges = cv.Canny(img,100,200) is maxVal and said to be 'sure to be edges'. Is there anyway to determine these (max/min) values ahead of any trial & error approach?
I have used code examples which utilize the Python cv2 module. But the edge detection is set up for simpler applications.
Is there any approach I can use to take the text out of the equation. For example: only detecting edge lines greater than a specified length?
Any suggestions would be appreciated.
Below is an example of edge detection (above image same min/max values) The outer edge of the page is clearly defined. The image is high contrast b/w. It has even lighting. I can't see a need for the use of an adaptive threshold. Simple global is working. Its just at what ratio to use it.
I don't have the answer to this yet. But to add. I now have the contours of the above doc.
I used find contours tutorial with some customization of the file loading. Note: removing words gives a thinner/cleaner outline.
Consider Otsu.
Its chief virtue is that it is adaptive to local
illumination within the image.
In your case, blank margins might be the saving grace.
Consider working on a series of 2x reduced resolution images,
where new pixel is min() (or even max()!) of original four pixels.
These reduced images might help you to focus on the features
that matter for your use case.
The usual way to deskew scanned text is to binarize and
then keep changing theta until "sum of pixels across raster"
is zero, or small. In particular, with few descenders
and decent inter-line spacing, we will see "lots" of pixels
on each line of text and "near zero" between text lines,
when theta matches the original printing orientation.
Which lets us recover (1.) pixels per line, and (2.) inter-line spacing, assuming we've found a near-optimal theta.
In your particular case, focusing on the ... leader dots
seems a promising approach to finding the globally optimal
deskew correction angle. Discarding large rectangles of
pixels in the left and right regions of the image could
actually reduce noise and enhance the accuracy of
such an approach.

How to draw contours around black areas in pixeld image?

i am quite new to Python and i try to write some code for image analysing.
Here is my initial image:
Initial image
After splitting the image in to the rgb channels, converting in to gradient, using a threshold and merging them back together i get the following image:
Gradient/Threshold
Now i have to draw contours around the black areas and get the size of the surrounded areas. I just dont know how to do it, since my trials with find/draw.contours in opencv are not succesfull at all.
Maybe someone also knows an easier way to get that from the initial image.
Hope someone can help me here!
I am coding in Python 3.
Try adaptive thresholding on the grayscale image of the input image.
Also play with the last two parameters of the adaptive thresholding. You will find good results as I have shown in the image. (Tip: Create trackbar and play with value, this will be quick and easy method to get best values of these params.)

Prepare Image for OCR

The images that I have gives me inconsistent results. My thought process is: my text is always in white font; if I can switch the pixel of my text to black and turned everything else to white or transparent, I will have better success.
My question is, what library or language is best for this? Do I have to turn my white pixel into some unique RGB, turn everything else to white or transparent, then find the unique RGB and make that black? Any help is appreciated.
Yes, if you could make the text pixels black and all the rest of the documents white you would have better success, although this is not always possible, there are processes that can help.
The median filter (and other low pass filters) can be used to remove noise present in the image.
erosion can also help to remove things that are not characters, like thin lines and also noise.
align the text is also a good idea, the OCR accuracy can drop considerably if the text is not aligned. To do this you could try the Hough transform followed by a rotation. Use the Hough transform to find a line in your text and then rotate the image in the same angle as the line.
All processing steps mentioned can be done with opencv or scikit-image.
Is also good to point out that there are many other ways to process text, too many to mention.

OpenCV find subjective contours like the human eye does

When humans see markers suggesting the form of a shape, they immediately perceive the shape itself, as in https://en.wikipedia.org/wiki/Illusory_contours. I'm trying to accomplish something similar in OpenCV in order to detect the shape of a hand in a depth image with very heavy noise. In this question, assume that skin color based detection is not working (actually it is the best I've achieved so far but it is not robust under changing light conditions, shadows or skin colors. Also various paper shapes (flat and colorful) are on the table, confusing color-based approaches. This is why I'm attempting to use the depth cam instead).
Here's a sample image of the live footage that is already pre-processed for better contrast and with background gradient removed:
I want to isolate the exact shape of the hand from the rest of the picture. For a human eye this is a trivial thing to do. So here are a few attempts I did:
Here's the result with canny edge detection applied. The problem here is that the black shape inside the hand is larger than the actual hand, causing the detected hand to overshoot in size. Also, the lines are not connected and I fail at detecting contours.
Update: Combining Canny and a morphological closing (4x4 px ellipse) makes contour detection possible with the following result. It is still waaay too noisy.
Update 2: The result can be slightly enhanced by drawing that contour to an empty mask, save that in a buffer and re-detect yet another contour on a merge of three buffered images. The line that combines the buffered images is is hand_img = np.array(np.minimum(255, np.multiply.reduce(self.buf)), np.uint8) which is then morphed once again (closing) and finally contour detected. The results are slightly less horrible than in the picture above but laggy instead.
Alternatively I tried to use an existing CNN (https://github.com/victordibia/handtracking) for detecting the approximate position of the hand's center (this step works) and then flood from there. In order to detect contours the result is put into an OTSU filter and then the largest contour is taken, resulting in the following picture (ignore black rectangles in the left). The problem is that some of the noise is flooded as well and the results are mediocre:
Finally, I tried background removers such as MOG2 or GMG. They are confused by the enormous amount of fast-moving noise. Also they cut off the fingertips (which are crucial for this project). Finally, they don't see enough details in the hand (8 bit plus further color reduction via equalizeHist yield a very poor grayscale resolution) to reliably detect small movements.
It's ridiculous how simple it is for a human to see the exact precise shape of the hand in the first picture and how incredibly hard it is for the computer to draw a shape.
What would be your recommended method to achieve an exact hand segmentation?
After two days of desperate testing, the solution was to VERY carefully apply thresholding to an well-preprocessed image.
Here are the steps:
Remove as much noise as you possibly can. In my case, denoising was done using Intel's pyrealsense2 (I'm using an Intel RealSense depth camera and the algorithms were written for that camera family, thus they work very well). I used rs.temporal_filter() and directly after rs.hole_filling_filter() on every frame.
Capture the very first frame. Besides capturing the exact distance to the table (for later thresholding), this step also saves a still picture that is blurred by a 100x100 px kernel. Since the camera is never mounted perfectly but slightly tilted, there's an ugly grayscale gradient going over the picture and making operations impossible. This still picture is then subtracted from every single later frame, eliminating the gradient. BTW: this gradient removal step is already incorporated in the screenshots shown in the question above
Now the picture is almost noise-free. Do not use equalizeHist. This does not simply increase the general contrast regularly but instead empathizes the remaining noise way too much. This was my main error I did in almost all experiments. Instead, apply a threshold (binary with fixed border) directly. The border is extremely thin, setting it at 104 instead of 205 makes a huge difference.
Invert colors (unless you have taken BINARY_INV in the previous step), apply contours, take the largest one and write it to a mask
VoilĂ !

convert image pixels from square to hexagonal

How can i convert the pixels of an image from square to hexagonal? Doing so i need to extract the rgb values from each hex pixel. Is there any library or function that simplify this process?
Example : Mona Lisa Hexagonal Pixel Shape
Nothing tried. Thanks
Here's a possible approach, though I am sure if you are able to write code to read, manipulate and use pixels from a file format that hasn't been invented yet, you should be able to create that file yourself ;-)
You could generate a hexagonal grid, using ImageMagick which is installed on most Linux distros and is available for OSX and Windows. Here, I am just doing things at the command-line in the Terminal, but there are Python, Perl, PHP, .Net, C/C++ and other bindings too - so take your pick.
First make a grid of hexagons - you'll have to work out the size you need, mine is arbitrary:
convert -size 512x256 pattern:hexagons hexagons.png
Now, fill in the hexagons, each with a different colour, I am just doing some examples of flood-filling here to give you the idea. Ideally, you would colour the first (top-left) hexagon with colour #000 and the next one across with #001 so that you could iterate through the coordinates of the output image as consecutive colours. Also, depending on your output image size, you may need to use a 32-bit PNG to accommodate the number of hexels (hexagonal pixels).
convert hexagons.png \
-fill red - draw "color 100,100 floodfill" \
-fill blue -draw "color 200,200 floodfill" \
colouredmask.png
Now iterate through all the colours, making every colour except that colour transparent. Note that I have added a black border just so you can see the context on StackOverflow's white background:
convert colouredmask.png -fill none +opaque red onecell.png
Now mask the original image with that mask and get the average colour of that one cell and write it to your yet-to-be-invented file format. Repeat for all cells/colours.
Note that the basic hexagon pattern is 30x18, so you should size your grid as multiples of that for it to tesselate properly.
Note that if you have lots of these to process, you should consider using something like GNU Parallel to take advantage of multiple cores. So, if you make a script called ProcessOneImage and you have 2,000 images to do, you would use:
parallel ProcessOneImage ::: *.png
and it will keep, say 8, jobs running all the time if your PC has 8 cores. There are many more options, try man parallel.
Fred has an Imagemagick script on his site that may do what you want: STAINEDGLASS
First of all, I think there is no such a function that is ready for you to perform the lattice conversion, thus you may need to implement the conversion process by yourself.
The lattice conversion is a re-sampling process, and it is also a interpolation process. There are many algorithms that have been developed in the hexagonal image processing papers.
Please see the example for you:

Categories