I have tried to create a contour map in python with a fault using KNearestNeighbors as the interpolation method. However, the graph came back as with multiple small contour areas, which I want to eliminate:
I tried to use OpenCV to find all enclosed contour lines and set a boundary value as the maximum area, then eliminate all areas smaller than the boundary value.
However, I seemed to fail using the findContours method, as it only found contours around the fault. All other contours failed to present. The resulting graph and my code are as follows:
img = cv2.imread('contor_line.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(gray,contours,-1,(0,0,255),1)
cv2.imshow("gray", gray)
cv2.waitKey(0)
This is my first time using OpenCV, so thank you for helping.
Try using canny before you find contours, or threshold your image, which will make finding contours easier and better.
Related
I am trying to find the contour with the largest area and fill the outside of the contour with white. I have looked at this Question
The solution works well when using many contours but when I try to use it with one contour it only shows the contour with the inside and outside black. I am trying to rather create a mask that only leaves the interior area of the contour. I am using max(contours, key=cv2.contourArea) to get the largest contour. Using OpenCv, Python
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()
i'm using openCV 2.4.9 version and the code i was referring to had the following line:
im2,contours,hier=cv2.findContours(im_th.copy(),cv2.RETR_EXTERNAL,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
I keep getting the error : "ValuesError : need more than 2 values to unpack "
I understand that findContour in 2.4.9 version of openCV returns only two values. But what are those values ?
In the three parameter version of this function, it returns the additional "im2" parameter. I'll cover contours and hierarchy returns briefly as they are well documented. The two return values depend on the two constants passed in. They are variants on the below.
Contours is a list, or tree of lists of points. The points describe each contour, that is, a vector that could be drawn as an outline around the parts of the shape based on it's difference from a background.
Hierarchy shows how the shapes relate to each other, layers as such - if shapes are on top of each other this can be determined here.
Experimenting with the im2 return value
The documentation at https://docs.opencv.org/3.3.1/d4/d73/tutorial_py_contours_begin.html suggests im2 is a modified image. I'm interested in this one return value because documentation doesn't really tell me what it does or is useful for.
Actual experimentation shows no difference.
My code:
import cv2
im = cv2.imread('shapes_and_colors.jpg')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imwrite("gray.jpg", imgray)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
cv2.imwrite("thresh.jpg", thresh)
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.imwrite("contour.jpg", im2)
Shapes and colors is a test image from pyimagesearch:
This is turned into a greyscale to threshold it:
I then apply a threshold, to get a binary image:
Finally I run findcontours - and just write the "im2" parameter to an image:
There is no visible difference. Perhaps a sophisticated image diff algorithm could find something I can't. I realise these are lossy JPG's which may confound that.
So far, I can't see that the im2 return value serves much of a purpose, but that contours and hierarchy are definitely useful.
I'll say that I'd expected to see something like drawcontours - but there is only one channel in that binary image, so even if it had, I'm not convinced I'd be able to see it. You cannot apply it to 32 bit images in it's normal mode. I also see no visible difference applying to the image in greyscale without thresholding.
The OpenCV documentation has all the details of the return types. May be you should go through that once. See this to understand hierarchy. To correct your error, use-
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
What you are currently using is for OpenCV 3.
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.
I'm working with the following input image:
I want to extract all the boxes inside original images as an individual images with position so that i can also construct it after doing some operations on it. Currently I'm trying to detect contours on the image using OpenCV. But the problem is it also extracts all the words inside the box. The output is coming something like this:
Is there is any way where i can set the dimensions of box to be taken or something else is required for this.
Fairly simple approach:
Convert to grayscale.
Invert the image (to avoid getting top level contour detected around whole image -- we want the lines white and background black)
Find external contours only (we don't have any nested boxes).
Filter contours by area, discard the small ones.
You could possibly also filter by bounding box dimensions, etc. Feel free to experiment.
Example Script
Note: for OpenCV 2.4.x
import cv2
img = cv2.imread('cnt2.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = 255 - gray # invert
contours,heirarchy = cv2.findContours(gray,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
for contour in contours:
area = cv2.contourArea(contour)
if area > 500.0:
cv2.drawContours(img,[contour],-1,(0,255,0),1)
cv2.imwrite('cnt2_out.png', img)
Example Output