How to straighten the edges of a mask in python opencv? - python

initial mask
I have the above mask which is roughly the shape of a trapezium and want to convert it to this. This would mean the sides were straightened - especially the front side of the mask. I want to alter this mask to straighten the edges and not just create a mask with a trapezium shape of the same size as I want to repeat this process on other masks without the trapezium shape and vary for other masks with different shapes, most not regular.
Is this possible?
Tried dilating and eroding without desired effects, although realised this would likely have little affect after.

For this task, I guess method cv2.findContours() will be helpful.
After you get the contours of your mask, you can play around with cv2.approxPolyDP() function to approximate your figure into some polygon. If you want your polygon to be convex, try cv2.convexHull(), also try cv2.boundingRect() or cv2.MinAreaRect(), though they will produce a right rectangle and rotated rectangle respectively.
Either way, try reading this article for more details on how to work with your mask. Though, there might be much more suitable functions in opencv for your current task.

Related

ways to reduce noise + smooth the image to create a mask for the largest object

I need your advice, guys! So I am trying to create a mask for a football (i.e. soccer) pitch, and if I only use filtering by the most common hue/saturation/value values, I get the following image
As you can see, the desired part is inside the grey boundary I drawn and there is a lot of noise here - trees, lines, external objects, and of course I would like to get rid of it. The desired outcome is something similar to this:
I thought about an algorithm that would transform the first image into another by analyzing each pixel's surrounding and color it white if more than threshold% of pixels into a (x, x) square is white, otherwise black.
Do you know if there is an implementation on openCV or similar libraries for this or I should build it from scratch?
Also, maybe you can propose other way to deal with the noise and external objects? I already tried the morphological transform and blurring techniques, but either I don't do it right or it doesn't work well for my problem.
Thank you in advance for your advice!
I actually found an easy implementation of the algo I proposed - I simply use cv2.blur on the image and then filter with cv2.inRange, so it does exactly what I wanted it to do.

How do I split a shape with conected pixels in to two parts in a binary image

My goal is to draw a rectangle border around the face by removing the neck area connected to the whole face area. All positive values here represent skin color pixels. Here I have so far filtered out the binary image using OpenCV and python. Code so far skinid.py
Below is the test image.
Noise removals have also been applied to this binary image
Up to this point, I followed this paper Face segmentation using skin-color map in videophone applications. And for the most of it, I used custom functions rather than using built-in OpenCV functions because I kind of wanted to do it from scratch. (although some erosion, opening, closing were used to tune it up)
I want to know a way to split the neck from the whole face area and remove it like this,
as I am quite new to the whole image processing area.
Perform a distance transform (built into opencv or you could write by hand its a pretty fun and easy one to write using the erode function iteratively, and adding the result into another matrix each round, lol slow but conceptually easy). On the binary image you presented above, the highest value in a distance transform (and tbh I think pretty generalized across any mug shots) will be the center of the face. So that pixel is the center of your box, but also that value (value of that pixel after the distance transform) will give you a pretty solid approx face size (since it is going to be the pixel distance from the center of the face to the horizontal edges of the face). Depending on what you are after, you may just be able to multiply that distance by say 1.5 or so (figure out standard face width to height ratio and such to choose your best multiplier), set that as your circle radius (or half side width for a box) and call it a day. Comment if you need anything clarified as I am pretty confident in this answer and would be happy to write up some quick code (in c++ opencv) if you need/ it would help.
(alt idea). You could tweak your color filter a bit to reject darker areas (this will at least in the image presented) create a nice separation between your face and neck due to the shadowing of the chin. (you may have to dial back your dilate/ closing op tho)

General questions about (canny) edge detection

I'm facing some general problems regarding the edge detection in an image (the image should be irrelevant for my question).
I want the canny edge detector to ignore a certain pixel value. For example: It should only look for edges if the gray value is not 0. Otherwise there will be "false edges" detected.
I usually use the cv2.canny function which works quite fast and well. Problem is, it is not customizable. So I took this code of a custom canny edge detector (https://rosettacode.org/wiki/Canny_edge_detector#Python) in order to customize it. It works but it's calculating the edges way too slow (It takes several minutes, whereas the cv2.canny function takes a fraction of a second).
This is my first problem.
Is there another way to make the cv2.canny function "ignore" pixels of a certein value. Imagine somewhere in the picture is a area filled with black (soo the image below). I don't want the edge detector to detect the edge of this black area.
Once I have some clear edges detected in my image, I want to create masks based on those edges. I couldn't find any examples for this online. So if anyone knows where to find a good tutorial on how to create masks from edges it would be great if you could help me out.
Thanks in advance
Here's an approach:
Calculate your Canny as usual using the fast OpenCV function.
Now locate all the black pixels in the image - you can do that with _,thr = cv2.threshold(im,1,255,cv2.THRESH_BINARY) and dilate those areas by 1 pixel with morphology to allow edges to be offset a little as they often are.
Multiply the normal Canny image with the mask you created so that anything it found in the black areas gets multiplied by zero, i.e. lost.

Smoothen edges of a non-binary image

I'm making some photo-editing tools in python using PIL (Python Imaging Library), and I was trying to make a program which converts a photo to its 'painted' version.
I've managed to make a program which converts a photo into its distinct colours, but the problem is that the algorithm I'm using is operating on every pixel, meaning that the resulting image has very jagged differences between colours.
Ideally, I'd like to smoothen out these edges, but I don't know how!
I've checked out this site for some help, but the method there produces quite different results to what I need.
My Starting Image:
My Image with Distinct Colours:
I would like to smoothen the edges in the image above.
Results of using the method which doesn't quite work:
As you can see, using the technique doesn't smoothen the edges into natural-looking curves; instead it creates jagged edges.
I know I should provide sample output, but suprisingly, I haven't actually got it, so I'll describe it as best as I can. Simply put, I want to smoothen the edges between the different colours.
I've seen something called a Gaussian blur, but I'm not quite sure as to how to apply it here as the answers I've seen always mention some sort of threshold, and are usually to do with binary images, so I don't think it can apply here.
Edge enhancement does the opposite of edge smoothing, so this is certainly not the tool you should use.
Unfortunately, there is little that you can do because edge smoothing will indeed smoothen the jaggies, but it will also destroy the true edges, resulting in a blurred image. Edge-preserving smoothing is also a dead-end.
You should have a look at the methods to extract the "cartoon part" of an image. There is a lot of literature on this topic, though often pretty sophisticated.
You can enhance the quality of your "Image with Distinct Colours" by applying a median filter with a radius of 2:
If you want to get "comic-like" dark edges, you can calculate the edges of the original image using a sobel filter, convert the edge map to grayscale, then multiply the resulting edge map with 2, inverse the map and add each non-white pixel of the edge map to the original image. This will result in:
This is of course only a starting point as the result leaves much to be desired, but it should give you a good idea about the basic concept.

Python/OpenCV: How can I infer an optimal structuring element from image data?

I have a sample of two-dimensional, black-and-white/binary barcodes that have been photographed.
The (colour) photographs typically suffer from all the usual suspects: blurring, distortion, contrast issues/lighting gradients, and erosion.
I am trying to reconstruct the original barcodes, which were once computer-generated pixel arrays of black/white values.
We should be able to exploit the images' spatial-frequency information to infer the dimensions of each pixel. The hope is to use this to better restore the original by convolving the image with such a structuring element defined by the data.
Although this is a very broad topic, I therefore have a very specific question:
What is the best way to establish a structuring element from image data in OpenCV/Python, without using prior knowledge of it?
(Assume for now that the underlying pixel scale is to some good approximation spatially invariant)
Note that I am not trying to execute the whole extraction pipeline: this question is simply about inferring an optimal structuring element from the data.
For example, the spatial kernel could be used as input to an unsharp mask, a la Python unsharp mask
References:
(1-D ideas) http://answers.opencv.org/question/174384/how-to-reconstruct-damaged-barcode, http://www.windytan.com/2016/02/barcode-recovery-using-priori.html
(Similar idea) Finding CheckerBoard Points in opencv for any random ChessBoard( pattern size not known)
(Sort of but not really, and answer-less) OpenCV find image frequencies
(Broad) https://en.wikipedia.org/wiki/Chessboard_detection
One way of doing this is:
Compute the Scharr gradient magnitude representations in both the x and y direction.
Subtract the y-gradient from the x-gradient. By performing this subtraction we are left with regions of the image that have high horizontal gradients and low vertical gradients.
Blur and threshold the image to filter out the noise.
Apply a closing kernel to the thresholded image to close the gaps between vertical stripes of the barcode.
Perform a series of dilations and erosions.
Find the largest contour in the image, which is now presumably the barcode.
More details and complete code can be found in this PyImageSearch blog post.

Categories

Resources