Python opencv optimal thresholding - python

I am trying to detect roi in my image dataset using Otsu thresholding. While in some cases results are on the point, some cases are not that good. I'm using the code below.
import cv2 as cv
import numpy as np
path = "./images/{}.png".format
for num in range(1000):
filename = path(num)
img = cv.imread(filename, cv.IMREAD_GRAYSCALE)
res = cv.threshold(img, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)[1]
res = np.hstack((img, res))
cv.imwrite(filename.replace(".png", "_.png"), res)
While these results are acceptable
These definitely need to be improved
How can I improve my code?

I suggest using the GRIP software to implement two image processing pipelines:
One that performs thresholding to find the center point and another to find all the other circles.
These pipelines can then be generated to Python OpenCV code and you can import them into your code (which I have already done for you).
Here is the center point pipeline:
It performs a simle HSV threshold followed by a find blob command
Here is the circle pipeline:
It performs a Laplacian transform (which is a one-sided Fourier Transform to detects the contrast changes which represent the edges of the circles), then Canny edge detection to find the edges of the circles, and then finds and filters the contours of the circles. To find the number of circle, you can divide the number of contours by 2 (inner and outer circle associated with each Laplacian ring)
Here is the link to download the GRIP software
Here is a link to all my files (including the auto-generated Python image processing pipeline)

Related

How to implement radial motion blur by Python OpenCV?

I can find motion blur kernel in horizontal and vertical direction, e.g. this link.
However, how can I implement radial motion blur like following pictures? I can find this functionality in Photoshop etc. I cannot find any kernel reference in website. How can I implement it by python opencv? Thanks
I don't think OpenCV has something like this built-in, but DIPlib has: dip.AdaptiveGauss(). It blurs the image with a different Gaussian at every pixel. One image indicates the orientation of the Gaussian, another one indicates the scaling.
This is how I replicated your blurred image:
import diplib as dip
img = dip.ImageRead('rose.jpg')
scale = dip.CreateRadiusCoordinate(img.Sizes()) / 100
angle = dip.CreatePhiCoordinate(img.Sizes())
out = dip.AdaptiveGauss(img, [angle, scale], [1,5])
dip.Show(out)
Disclaimer: I'm an author of DIPlib.

How do I crop the black background of the image using OpenCV in Python?

So I have an image processing task at hand which requires me to crop a certain portion of an image. I have no prior experience of OpenCV. I would like to know of a certain approach where I should be headed.
Sample Input Image:
Sample Output Image:
What I initially thought was to convert the image to a bitmap and remove pixels that are below or above a certain threshold. Since I am free to use OpenCV and Python, I would like to know of any automated algorithm that does so and if not, what should be the right approach for such a problem. Thank you.
Applying a simple threshold should get rid of the background, provided it's always darker than the foreground. If you use the Otsu thresholding algorithm, it should choose a good partition for you. Using your example as input, this gives:
Next you could compute the bounding box to select the region of the foreground. Provided the background is distinct enough and there are no holes, this gives you the resulting rect:
[619 x 96 from (0, 113)]
You can then use this rect to crop the original, to produce the desired result:
I wrote the code to solve this in C++. A rough translation into Python would look something like this:
import cv2 as cv
img = cv.imread(sys.argv[1])
grayscale = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
thresholded = cv.threshold(grayscale, 0, 255, cv.THRESH_OTSU)
imwrite("otsu.png", thresholded)
bbox = cv.boundingRect(thresholded)
x, y, w, h = bbox
print(bbox)
foreground = img[y:y+h, x:x+w]
imwrite("foreground.png", foreground)
This method is fast and simple. If you find you have some white holes in your background which enlarge the bounding box, try applying an erosion operator.
FWIW I very much doubt you would get results like this as predictably or reliably using NNs.
The thresholding seems like a good approach. An overkill would be a neural network but you probably don't have enough data to train (:D) anyways check out this link.
you should be able to do something like:
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('img.png')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU
NN would be a overkill! You can do edge detection and get the extreme horizontal lines as boundaries. Then crop only the roi within these two lines.

How to detect change in colours in the image below?

I need to identify the pixels where there is a change in colour. I googled for edge detection and line detection techniques but am not sure how or in what way can these be applied.
Here are my very naive attempts:
Applying Canny Edge Detection
edges = cv2.Canny(img,0,10)
with various parameters but it didn't work
Applying Hough Line Transform to detect lines in the document
The intent behind this exercise is that I have an ill-formed table of values in a pdf document with the background I have attached. If I am able to identify the row boundaries using colour matching as in this question, my problem will be reduced to identifying columns in the data.
Welcome to image processing. What you're trying to do here is basically trying to find the places where the change in color between neighboring pixels is big, thus where the derivative of pixel intensities in the y direction is substantial. In signal processing, those are called high frequencies. The most common detector for high frequencies in images is called Canny Edge Detector and you can find a very nice tutorial here, on the OpenCV website.
The algorithm is very easy to implement and requires just a few simple steps:
import cv2
# load the image
img = cv2.imread("sample.png")
# convert to grayscale
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# resize for the visualization purposes
img = cv2.resize(img, None, img, fx=0.4, fy=0.4)
# find edges with Canny
edges = cv2.Canny(img, 10, 20, apertureSize=3)
# show and save the result
cv2.imshow("edges", edges)
cv2.waitKey(0)
cv2.imwrite("result.png", edges)
Since your case is very straightforward you don't have to worry about the parameters in the Canny() function call. But if you choose to find out what they do, I recommend checking out how to implement a trackbar and use it for experimenting. The result:
Good luck.

Suggestion to detecting straight lines on a sand plate, python

I am working on a project that requires detecting lines on a plate of sand. The lines are hand-drew by user so that are not exactly "straight" (see photo). And because of the sand, the lines are quite hard to distinguish.
I tried cv2.HoughLines from OpenCV but didn't achieve good results. So any suggestion on the detecting method? And welcome for suggestion to improve the clarity of the lines. I am thinking of putting a few led light surrounding the plate.
Thanks
The detecting method depends a lot on how much generality you require: is the exposure and contrast going to change from one image to another? Is the typical width of lines going to change? In the following, I assume that such parameters do not vary much for your applications, please correct me if I'm wrong.
I'll be using scikit-image, a common image processing package for Python. If you're not familiar with this package, documentation can be found on http://scikit-image.org/, and the package is bundled with all installations of Scientific Python. However, the algorithms that I use are also available in other tools, like opencv.
My solution is written below. Basically, the principle is
first, denoise the image. Life is usually simpler after a denoising step. Here I use a total variation filter, since it results in a piecewise-constant image that will be easier to threshold. I enhance dark regions using a morphological erosion (on the gray-level image).
then apply an adaptive threshold that varies locally in space, since the contrast varies through the image. This operation results in a binary image.
erode the binary image to break spurious links between regions, and keep only large regions.
compute a measure of the elongation of the regions to keep only the most elongated ones. Here I use the ratio of the eigenvalues of the inertia tensor.
Parameters that are the most difficult to tune is the block size for the adaptive thresholding, and the minimum size of regions to keep. I also tried a Canny filter on the denoised image (skimage.filters.canny), and results were quite good, but edges were not always closed, you might also want to try an edge-detection method such as a Canny filter.
The result is shown below:
# Import modules
import numpy as np
from skimage import io, measure, morphology, restoration, filters
from skimage import img_as_float
import matplotlib.pyplot as plt
# Open the image
im = io.imread('sand_lines.png')
im = img_as_float(im)
# Denoising
tv = restoration.denoise_tv_chambolle(im, weight=0.4)
ero = morphology.erosion(tv, morphology.disk(5))
# Threshold the image
binary = filters.threshold_adaptive(ero, 181)
# Clean the binary image
binary = morphology.binary_dilation(binary, morphology.disk(8))
clean = morphology.remove_small_objects(np.logical_not(binary), 4000)
labels = measure.label(clean, background=0) + 1
# Keep only elongated regions
props = measure.regionprops(labels)
eigvals = np.array([prop.inertia_tensor_eigvals for prop in props])
eigvals_ratio = eigvals[:, 1] / eigvals[:, 0]
eigvals_ratio = np.concatenate(([0], eigvals_ratio))
color_regions = eigvals_ratio[labels]
# Plot the result
plt.figure()
plt.imshow(color_regions, cmap='spectral')

Face morphing using opencv

Can I get some ideas on how to morph the face in a live video using opencv? I have tried Face substitution but it is implemented using openFrameworks.
I would like to implement the same using opencv. Is there any other methods available in opencv than diirectly porting Face substituion code from openFrameworks to Opencv?
I have also gone through this link, but few people have mentioned as the face morphing is deprecated in opencv?
I recently wrote an article on face morphing using OpenCV. I have shared the code in C++ / Python. You can find the details here
http://www.learnopencv.com/face-morph-using-opencv-cpp-python/
but the basic idea is as follows.
Find Point Correspondences in the two input images.
Do Delaunay triangulation on the points.
The amount of morphing is controlled by a parameter alpha. E.g .for alpha = 0, you will get Ted Cruz in the example below, and for alpha = 1. you will get Hillary Clinton. For any other alpha, it will be the blend between the two. Use alpha to calculate the location of the points in the output ( morphed ) image by taking a weighted average of the two input image points.
Calculate the affine transform between every triangle in the input images and the destination image ( morphed image ).
Warp triangle from each input images to the output image, and blend the pixels based on alpha. Do this for every triangle and you get the output morphed image.
Hope this helps.
I don't know any libraries that do this specifically, but you could cobble together something yourself. You'd need a set of common fiducial points that you reference in all faces. Then you'd want to use those point to do Delaunay triangulation on it.
Now you can either do the transform directly from one face chassis to the other, or you can write it to an intermediary normalized face, make changes to that and then write it anywhere.
Here are the steps of the face morphing implementation with mesh-warping algorithm (you could implement it with opencv or python scipy / scikit-image):
Defining Correspondences: find point-correspondences between the faces to be aligned using facial landmarks (detect landmarks with dlib, e.g.,).
Delaunay Triangulation: You need to provide a triangulation (Delaunay triangulation, e.g.) of these points that will be used for morphing (with scipy.spatial's Delaunay, e.g.,).
Computing the Mid-way (morphed) Face: computing the average shape, warp both faces into that shape (calculate the affine transforms using the triangles in source image and the corresponding ones using the morphed image and warp the points inside the triangles and alpha-blend the warped images to obtain the final morphed image, using scikit-image's warp(), e.g.,).
The next animation shows the animated output from an implementation of mesh-warping algorithm with scipy / numpy / scikit-image in python (sequence of morph images starting from Monalisa image to Leonardo da Vinci image). This can be found here too.
Another popular algorithm is Beier-neely morphing algorithm (https://en.wikipedia.org/wiki/Beier%E2%80%93Neely_morphing_algorithm)
Check a face-morphing tool in Python using OpenCV

Categories

Resources