OpenCV Extract open edges from image after using Canny algorithm - python

I'm trying to extract the edge of a drop from the following image which I've first applied cv2.Canny() onto:
I tried using cv2.findContours() (and taking the longest contour found) but this ends up being a closed loop around the drop's 1 pixel edge (shown exaggerated in blue).
Is there a way to extract just a single open edge (as a list of (x, y) points, similar to the structure of a contour returned by findContours()) that goes around the profile of the drop?
Images:
Original Image
After applying Canny

Related

Extract Data from an Image with Python/OpenCV/Tesseract?

I'm trying to extract some contents from a cropped image. I tried pytesseract and opencv template matching but the results are very poor. OpenCV template matching sometimes fails due to poor quality of the icons and tesseract gives me a line of text with false characters.
I'm trying to grab the values like this:
0:26 83 1 1
Any thoughts or techniques?
A technique you could use would be to blur your image. From what it looks like, the image is kind of low res and blurry already, so you wouldn't need to blur the image super hard. Whenever I need to use a blur function in Opencv, I normally choose the gaussian blur, as its technique of blurring each pixel as well as each surrounding pixel is great. Once the image is blurred, I would threshold, or adaptive threshold the image. Once you have gotten this far, the image that should be shown should be mostly hard lines with little bits of short lines mixed between. Afterwards, dilate the threshold image just enough to have the bits where there are a lot of hard edges connect. Once a dilate has been performed, find the contours of that image, and sort based on their height with the image. Since I assume the position of those numbers wont change, you will only have to sort your contours based on the height of the image. Afterwards, once you have sorted your contours, just create bounding boxes over them, and read the text from there.
However, if you want to do this the quick and dirty way, you can always just manually create your own ROI's around each area you want to read and do it that way.
First Method
Gaussian blur the image
Threshold the image
Dilate the image
Find Contours
Sort Contours based on height
Create bounding boxes around relevent contours
Second Method
Manually create ROI's around the area you want to read text from

Extracting data from graphs in a scanned document

EDIT: This is a deeper explanation of a question I asked earlier, which is still not solved for me.
I'm currently trying to write some code that can extract data from some uncommon graphs in a book. I scanned the pages of the book, and by using opencv I would like to detect some features ofthe graphs in order to convert them into useable data. In the left graph I'm looking for the height of the "triangles" and in the right graph the distance from the center to the points where the dotted lines intersect with the gray area. In both cases I would like to convert these values into numeric data for further usage.
For the left graph, I thought of detecting all the individual colors and computing the area of each sector by counting the amount of pixels in that color. When I have the area of these sectors, I can easily calculate their heights, using basic math. The following code snippet shows how far I've gotten already with identifying different colors. However I can't manage to make this work accurately. It always seems to detect some colors of other sectors as well, or not detect all pixels of one sector. I think it has something to do with the boundaries I'm using. I can't quite figure out how to make them work. Does someone know how I can determine these values?
import numpy as np
import cv2
img = cv2.imread('images/test2.jpg')
lower = np.array([0,0,100])
upper = np.array([50,56,150])
mask = cv2.inRange(img, lower, upper)
output = cv2.bitwise_and(img, img, mask = mask)
cv2.imshow('img', img)
cv2.imshow('mask', mask)
cv2.imshow('output', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
For the right graph, I still have no idea how to extract data from it. I thought of identifying the center by detecting all the dotted lines, and then by detecting the intersections of these dotted lines with the gray area, I could measure the distance between the center and these intersections. However I couldn't yet figure out how to do this properly, since it sounds quite complex. The following code snippet shows how far I've gotten with the line detection. Also in this case the detection is far from accurate. Does someone have an idea how to tackle this problem?
import numpy as np
import cv2
# Reading the image
img = cv2.imread('test2.jpg')
# Convert the image to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Apply edge detection
edges = cv2.Canny(gray,50,150,apertureSize = 3)
# Line detection
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength=50,maxLineGap=20)
for line in lines:
x1,y1,x2,y2 = line[0]
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)
cv2.imwrite('linesDetected.jpg',img)
For the left image, using your approach, try to look at the RGB histogram, the colors should be significant peaks, if you would like to use the relative area of the segments.
Another alternative could be to use Hough Circle Transform, which should work on circle segments. See also here.
For the right image ... let me think ...
You could create a "empty" diagram with no data inside. You know the locations of the circle segment ("cake pieces"). Then you could identify the area where the data is (the dark ones), either by using a grey threshold, an RGB threshold, or Find Contours or look for Watershed / Distance Transform.
In the end the idea is to make a boolean overlay between the cleared image and the segments (your data) that was found. Then you can identify which share of your circle segments is covered, or knowing the center, find the farthest point from the center.

shared boundaries of contours in opencv

I am converting an image(full-pixel semantic segmentation mask) with each object corresponding to a constant color(no illumination or other effects; aliased image) to find the contour of each object. Ideally, I am expecting a shared boundary between adjacent objects.
My current approach does not provide a shared boundary because I am isolating each connected component. The solution has boundaries overlapping with between adjacent contours. Can you suggest an approach for shared boundaries?
Approach:
Create a mask for each of the unique colors.
Find the connected components for each of the object in the mask
Find the contour for each connected component.
input image-https://drive.google.com/file/d/1-12gVzPUueXSOpg4EOSRxi1Dx2nBIFQ9/view?usp=sharing
output image generated from contours(identical to the input but has overlapping contours)-https://drive.google.com/file/d/19WzIVe3iXU6IibEojNgHlEaNO3FuLgdW/view?usp=sharing
overlapping contours in the red doodle, see yellow and green-https://drive.google.com/file/d/1g02cvbwS1toNIbj4icZunRx70I-6i923/view?usp=sharing
image generated from contours looks similar but the below image shows the overlapping contours

Image Cropping using canny edges detection [duplicate]

This question already has answers here:
Split text lines in scanned document
(2 answers)
Closed 4 years ago.
I have generated the edges using Canny edge detector now want to crop source image by those edges.
Is there any way to get.
Left and Top Most 255 pixel location of image.
Right and Top Most 255 pixel location of image.
Left and Bottom Most 255 pixel location of image.
Right and Bottom Most 255 pixel location of image.
And crop that image based on that location.
Using open cv or any other library using python.
There may be better solutions but I think you can implement an algorithm.
Start by drawing a square that FULLY captures the child set of pixels. Then, slowly bringing in the sides one at a time until they encounter a 255 pixel. Once you've fully pulled in all 4 sides, you will have your desired area to crop.
You could also use four simple (one-liner) For loops to check for "first white pixel". Since pixels x-pos starts at top/left, Using x++ to check forward and x-- to check backwards (from right-side).

Remove border of license plates with OpenCV (python)

I cropped license plates but they have some borders I want to remove the borders to segment characters, I tried to use Hough transform but It's not a promising approach. Here is the samples of license plates:
Is there any simple way to do that?
I have a naïve solution for one image. You have to tune some parameters to generalize it for the other images.
I chose the third image due to its clarity.
1. Threshold
In such cases the first step is to reach an optimal threshold, where all the letters/numbers of interest are converted to same pixel values. As a result I got the following:
2. Finding Contour and Bounding Region
Now I found the external contour present in the image to retain the letter/numbers. After finding it I found the bounding rectangle for the corresponding contour:
3. Cropping
Next I used the parameters returned from bounding the contour and used them to crop the image:
VOILA! There you have your region of interest!
Note:
This approach would work if all the images are taken in a similar manner and for the same color space. The second image provided has a different color. Hence you will have to alter the threshold parameters to segment your ROI properly.
You can also perform some morphological operations on the threshold image to obtain a better ROI.

Categories