Select lines in traced image in python - python

I'm not very good with programming. Is there any way to be able to select and mask lines of a certain length and basic linear shapes like circles, parabola, squares, etc? I want to then use a selected - mouse clicked - line/shape in another pipeline, so preferably having it masked and stored in another image
I currently have this basic open cv python code which is able to give me a traced out image:
# Reading the required image in
# which operations are to be done.
# Make sure that the image is in the same
# directory in which this python program is
img = cv2.imread('/workspaces/85332242/Personal/Unknown.jpeg')
# Convert the img to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Apply edge detection method on the image
edges = cv2.Canny(gray, 50, 200,apertureSize = 3)
cv2.imwrite('linesDetected.jpg', edges)
This produces:
I'd like to be able to click and select separate lines in this image.
Any help would be much appreciated!

Related

OpenCV: detect text from multiple boundaries simultaneously

I'm currently trying to write a script to detect text in an OBS video stream using Python/OpenCV.
From every n-th frame, I need to detect text in several specific boundaries (Example can be found in the attachment). The coordinates of these boundaries are constant for all video frames.
My questions:
is OpenCV the best approach to solve my task?
what OpenCV function should I use to specify multiple boundaries for text detection?
is there a way to use a video stream from OBS as an input to my script?
Thank you for your help!
I can't say anything about OBS but openCV + Tessaract should be all you need. Since you know the location of the text very precisely it will be very easy to use. here is a quite comprehensive tutorial on using both, which includes bits on finding where the text is in the image.
The code could look like this:
img = cv2.imread("...") # or wherever you get your image from
region = [100, 200, 200, 400] # regions where text is
# Tessaract expects rgb open cv uses bgr
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
output = pytesseract.image_to_string(img_rgb[region[0]:region[2], region[1]: region[3]])
The only other steps that might be required are to invert the image in order to make it dark text on a light background. Those tips can be found here. For example removing the red background that is in one of the boxes you highlighted might help with accuracy, which can be achieved by thresholding on red values img_rgb[img_rgb[...,0] > 250] = [255, 255,255].
As for reading your images in, this other question might help.

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()

How to make shadowed part of background count as background (picture below) with OpenCV in Python?

I am very new to OpenCV(and to StackOverflow). I'm writing a program with OpenCV which takes a picture with an object (i.e. pen(rice, phone) put on paper) and calculates what percent does the object make of the picture.
Problem I'm facing with is when I threshold image (tried adaptive and otsu) photo is a little bit shadow around edges:
Original image
Resulted picture
And here's my code:
import cv2
img = cv2.imread("image.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
b,g,r = cv2.split(img)
th, thresh = cv2.threshold(b, 100, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
cv2.imwrite("image_bl_wh.png", thresh)
Tried to blur and morphology, but couldn't do it.
How can I make my program count that black parts around the picture as background and is there more better and easier way to do it?
P.S. Sorry for my English grammar mistakes.
This is not a programmatic solution but when you do automatic visual inspection it is the first thing you should try: Improve your set-up. The image is simply darker around the edges so increasing the brightness when recording the images should help.
If that's not an option you could consider having an empty image for comparison. What you are trying to do is background segmentation and there are better ways than simple color thresholding they do however usually require at least one image of the background or multiple images.
If you want a software only solution you should try an edge detector combined with morphological operators.

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.

I need to break original image into sub parts based on shape

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

Categories

Resources