How to detect change in colours in the image below? - python

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.

Related

Python opencv optimal thresholding

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)

Image Registration of Scanned Text Forms

We print 500 bubble surveys, get them back, and scan them in a giant batch giving us 500 PNG images.
Each image has a slight variations in alignment, but identical size and resolution. We need to register the images so they're all perfectly aligned. (With the next step being semi-automated scoring of the bubbles).
If these were 3D-MRI images, I could accomplish this with a single command line utility; But I'm not seeing any such tool for aligning scanned text documents.
I've played around with opencv as described in Image Alignment (Feature Based) using OpenCV, and it produces dynamite results when it works, but it often fails spectacularly. That approach is looking for documents hidden within natural scenes, a much harder problem than our case where the images are just rotated and translated in 2D, not 3.
I've also explored imreg_dft, which runs consistently but does a very poor job -- presumably the dft approach is better on photographs than text documents.
Does a solution for Image Registration of Scanned Forms already exist? If not, what's the correct approach? Opencv, imreg_dft, or something else?
Similar prior question: How to find blank field on scanned document image
What you can try is using the red outline of the answer boxes to create a mask where you can select the outline. I create a sample below. You can also remove the blue letters by creating a mask for the letters, inverting it, then apply it as a mask. I didn't do that, because he image of the publisher is low-res, and it caused issues. I expect your scans to perform better.
When you have the contours of the boxes you can transform/compare them individually (as the boxes have different sizes). Or you can use the biggest contour to create a transform for the entire document.
You can then use minAreaRect to find the cornerpoints of the contours. Threshold the contourArea to exclude noise / non answer area's.
import cv2
import numpy as np
# load image
img = cv2.imread('Untitled.png')
# convert to hsv colorspace
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# define range of image bachground in HSV
lower_val = np.array([0,0,0])
upper_val = np.array([179,255,237])
# Threshold the HSV image
mask = cv2.inRange(hsv, lower_val, upper_val)
# find external contours in the mask
contours, hier = cv2.findContours(mask, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# draw contours
for cnt in contours:
cv2.drawContours(img,[cnt],0,(0,255,0),3)
# display image
cv2.imshow('Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Canny transform VS threshed image for HoughCircle

I'm try to build a robust coin detection on images using HoughCircle with these params :
blured_roi = cv2.GaussianBlur(region_of_interest, (23, 23), cv2.BORDER_DEFAULT)
rows = blured_roi.shape[0]
circles = cv2.HoughCircles(blured_roi, cv2.HOUGH_GRADIENT, 0.9, rows/8,
param1=30, param2=50, minRadius=30, maxRadius=90)
The region of interest could be (300x300) or (1080x1920). So the minRadius and maxRadius aren't really helping here. But they are approximately the size of my coin in each type of image shape.
So to achieve that I tried many things. First of all, using simple GRAY image with a GaussianBlur filter.
It works on most of cases but if my coin border are similar tint as the background, the GRAY scale image will not really help to detect the right radius of my circle take a look at this example :
In second time, I tried to use edges of the coin to detect circles with Canny Transform, but as you can see above the Canny filter not works as I hoped. So I applied a GaussianBlur of (13, 13).
I also know that there is another canny transform call inside the HoughCircle method, but I wanted to be sure I'll get edges of the coin, because I'm losing them while blurring with GaussianBlur.
Finally I tried using a threshed image, but I can't understand why it didn't works as well as excepted, because on this image we can hope there will never have any noises because it's only black&white (?), and the circle is almost perfect. And applied a GaussianBlur of (9, 9).
Here you can see it failed to detect the coin on the threshed image, but it works with the canny edges image. But in many other cases Hough Transform on edges detection give an unperfected result, and I feel confiant about threshed image which as you can see reveal a nice circle.
I would like to understand why it didn't works on the threshed image (like the example above), and what I could do to make it works.
EDIT 1: So I discovered the different type of BORDER to specify in the GaussianBlur method. I thought it would be really useful to improve the hough circle detection on the Threshed image, but it didn't goes as well as excepted.

Find the contour with largest enclosing area using OpenCV (Python)

I have an image Original Image, and I would like to find the contour that encloses the box in the image. The reason for doing this, is I would like to then crop the image to the bounding box, and then perform further image processing on this cropped image.
I have tried detecting Canny edges, however they seem not to be connecting as I want them to. Attached is an image of how the canny edges look. Canny edges
gray = img[:,:,1]
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(blurred, 20, 60)
What is the best way to find the bounding box from the original image?
Many thanks.
Let me know how I can make this question clearer if possible too!
I assume the following: (if this is not the case you should specify such things in your question)
You know the size of the box
The size is always the same
The perspective is always the same
The box is always completely within the field of fiew
The box is not rotated
Use a few scan lines across the image to find the transition from black background to box (in x and y)
Threshold exceeded, max gradient or whatever suits you best.
Discard outliers, use min and max coordinates to position the fixed size ROI over your box.
There are many other ways to find the center positon of that fixed ROI like
threshold, distance transform, maximum
or
threshold, blob search, centroid/contour
You could also do some contour matching.
I recommend you improve your setup so the background illumination does not exceed the box border (left/right is better than top/bottom). Then everything becomes easy.
Your edge image looks terrible btw. Check other methods or improve your Canny parameters.

How to properly detect corners using Harris detector with OpenCV?

I'm testing some image processing to obtain minutiae from digital fingerprints. I'm doing so far:
Equalize histogram
Binarize
Apply Zhang-Suen algorithm for lines thinning (this is not working properly).
Try to determine corners in thinned image and show them.
So, the modifications I'm obtaining are:
However, I can't get to obtain possible corners in the last image, which belongs to thinned instance of Mat object.
This is code for trying to get corners:
corners_image = cornerHarris(thinned,1,1,0.04)
corners_image = dilate(corners_image,None)
But trying imshow on the resulting matrix will show something like:
a black image.
How should I determine corners then?
Actually cv::cornerHarris returns corener responses, not corners itself. Looks like responses on your image is too small.
If you want to visualize corners you may get responses which are larger some threshold parameter, then you may mark this points on original image as follows:
corners = cv2.cvtColor(thinned, cv2.COLOR_GRAY2BGR)
threshold = 0.1*corners_image.max()
corners [corners_image>threshold] = [0,0,255]
cv2.imshow('corners', corners)
Then you can call imshow and red points will correspond to corner points. Most likely you will need to tune threshold parameter to get results what you need.
See more details in tutorial.

Categories

Resources