How to find longest uninterrupted edge using canny? - python

I have a problem with canny edge detection in python.
my starting picture is a normal picture of a bill like I have added in the post.
I detect the edges with canny without any problems but I want to know where the longest detected edges are in the picture.
Here is the input image
and here is the output image.
Now I want to know the longest edge in the output image to cut of the unnecessary parts of the picture, but I do not know how...
My Code:
# Read reference image
#refFilename = RefRefFileCalculation(row)
refFilename = "C:\\Maturaprojekt\\Test 1\\30Zeilen.JPG"
print("Reading reference image : ", refFilename)
imReference = cv2.imread(refFilename, cv2.IMREAD_COLOR)
# Read image to be aligned
imFilename = save_path
print("Reading image to align : ", imFilename);
im = cv2.imread(imFilename, cv2.IMREAD_COLOR)
print("Aligning images ...")
# Registered image will be resotred in imReg.
# The estimated homography will be stored in h.
imReg, h = alignImages(im, imReference)
# Write aligned image to disk.
outFilename = "C:\\Maturaprojekt\\Test 1\\gedreht\\" + sample_names[i]
print("Saving aligned image : ", outFilename);
cv2.imwrite(outFilename, imReg)
# Load the image file
image = cv2.imread(save_path)
# Check if image was loaded improperly and exit if so
if image is None:
sys.exit('Failed to load image')
# Detect edges in the image. The parameters control the thresholds
edges = cv2.Canny(image, 100, 700, apertureSize=5)
# Display the output in a window
cv2.imwrite("C:\\Maturaprojekt\\Edge Detection Test 1\\cropped\\" + sample_names[i], edges)
i = i+1

Related

Python Pytesseract - unable to read the image

I am new to pyteseract OCR. I was able to read simple pic and get the test message. I am unable to read test from attached png file. From the attached image, i am trying to extract ishSilver and (SLV) in text.
I would appreciate it if you could help on this. Thank you in advance.
from PIL import Image
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r'C:\Tesseract-OCR\tesseract.exe' # actual path to tesseract
im = Image.open('Images/' + '1680.png')
# Size of the image in pixels (size of orginal image)
# (This is not mandatory)
width, height = im.size
# Setting the points for cropped image
left = width*.88
top = 0
right = width
bottom = height
# Cropped image of above dimension
# (It will not change orginal image)
im1 = im.crop((left, top, right, bottom))
# Capturing the image in image viewer and converting to text
text = pytesseract.image_to_string(im1, lang="eng")
print(text)
print("/n")
# Finding the "(" and ")" to the actual stock ticker and save the text in symbol for placeorder to access the file
ticker = text[text.find("(")+1:text.find(")")]
print(ticker)
enter image description here
enter image description here
enter image description here

Resizing non uniform images with precise face location

I work at a studio that does school photos and we are trying to make a script to eliminate the job of cropping each photo to a template. The photos we work with are fairly uniform but they vary in resolution and head position a bit. I took up the mantle of trying to write the script with my fairly limited Python knowledge and through a lot of trial and error and online resources I think I have got most of the way there.
At the moment I am trying to figure out the best way to have the image crop from the NumPy array with the head where I want and I just cant find a good flexible solution. The head needs to be positioned slightly differently for pose 1 and pose 2 so its needs to be easy to change on the fly (Probably going to implement some sort of simple GUI to input stuff like that, but for now I can just change the code).
I also need to be able to change the output resolution of the photo so they are all uniform (2000x2500). Anyone have any ideas?
At the moment this is my current code, it just saves the detected face square:
import cv2
import os.path
import glob
# Cascade path
cascPath = 'haarcascade_frontalface_default.xml'
# Create the haar cascade
faceCascade = cv2.CascadeClassifier(cascPath)
#Check for output folder and create if its not there
if not os.path.exists('output'):
os.makedirs('output')
# Read Images
images = glob.glob('*.jpg')
for c, i in enumerate(images):
image = cv2.imread(i, 1)
# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Find face(s) using cascade
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1, # size of groups
minNeighbors=5, # How many groups around are detected as face for it to be valid
minSize=(500, 500) # Min size in pixels for face
)
# Outputs number of faces found in image
print('Found {0} faces!'.format(len(faces)))
# Places a rectangle on face
for (x, y, w, h) in faces:
imgCrop = image[y:y+h,x:x+w]
if len(faces) > 0:
#Saves Images to output folder with OG name
cv2.imwrite('output/'+ i, imgCrop)
I can crop using it like this:
# Crop Padding
left = 300
right = 300
top = 400
bottom = 1000
for (x, y, w, h) in faces:
imgCrop = image[y-top:y+h+bottom, x-left:x+w+right]
but that outputs pretty random resolutions and changes based on the image resolution
TL;DR
To set a new resolution with the dimension, you can use cv2.resize. There may be a pixel loss so you can use the interpolation method.
The newly resized image may be in BGR format, so you may need to convert to RGB format.
cv2.resize(src=crop, dsize=(2000, 2500), interpolation=cv2.INTER_LANCZOS4)
crop = cv2.cvtColor(crop, cv2.COLOR_BGR2RGB) # Make sure the cropped image is in RGB format
cv2.imwrite("image-1.png", crop)
Suggestion:
One approach is using python's face-recognition library.
The approach is using two sample images for training.
Predict the next image based on training images.
For instance, The followings are the training images:
We want to predict the faces in the below image:
When we get the facial encodings of the training images and apply to the next image:
import face_recognition
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
# Load a sample picture and learn how to recognize it.
first_image = face_recognition.load_image_file("images/ex.jpg")
first_face_encoding = face_recognition.face_encodings(first_image)[0]
# Load a second sample picture and learn how to recognize it.
second_image = face_recognition.load_image_file("images/index.jpg")
sec_face_encoding = face_recognition.face_encodings(second_image)[0]
# Create arrays of known face encodings and their names
known_face_encodings = [
first_face_encoding,
sec_face_encoding
]
print('Learned encoding for', len(known_face_encodings), 'images.')
# Load an image with an unknown face
unknown_image = face_recognition.load_image_file("images/babes.jpg")
# Find all the faces and face encodings in the unknown image
face_locations = face_recognition.face_locations(unknown_image)
face_encodings = face_recognition.face_encodings(unknown_image, face_locations)
# Convert the image to a PIL-format image so that we can draw on top of it with the Pillow library
# See http://pillow.readthedocs.io/ for more about PIL/Pillow
pil_image = Image.fromarray(unknown_image)
# Create a Pillow ImageDraw Draw instance to draw with
draw = ImageDraw.Draw(pil_image)
# Loop through each face found in the unknown image
for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
best_match_index = np.argmin(face_distances)
draw.rectangle(((left, top), (right, bottom)), outline=(0, 0, 255), width=5)
# Remove the drawing library from memory as per the Pillow docs
del draw
# Display the resulting image
plt.imshow(pil_image)
plt.show()
The output will be:
The above is my suggestion. When you create a new resolution with the current image, there will be a pixel loss. Therefore you need to use an interpolation method.
For instance: after finding the face locations, select the coordinates in the original image.
# Add after draw.rectangle function.
crop = unknown_image[top:bottom, left:right]
Set new resolution with the size 2000 x 2500 and interpolation with CV2.INTERN_LANCZOS4.
Possible Question: Why CV2.INTERN_LANCZOS4?
Of course, you can select whatever you like, but in this post CV2.INTERN_LANCZOS4 was suggested.
cv2.resize(src=crop, dsize=(2000, 2500), interpolation=cv2.INTER_LANCZOS4)
Save the image
crop = cv2.cvtColor(crop, cv2.COLOR_BGR2RGB) # Make sure the cropped image is in RGB format
cv2.imwrite("image-1.png", crop)
Outputs are around 4.3 MB Therefore I can't display in here.
From the final result, we clearly see and identify faces. The library precisely finds the faces in the image.
Here what you can do:
Either you can use the training images of your own-set, or you can use the example above.
Apply the face-recognition function for each image, using the trained face-locations and save the results in the directory.
here is how I got it to crop how I wanted, this is added right below the "output number of faces" function
#Get the face postion and output values into variables, might not be needed but I did it
for (x, y, w, h) in faces:
xdis = x
ydis = y
w = w
h = h
#Get scale value by dividing wanted head hight by detected head hight
ws = 600/w
hs = 600/h
#scale image to get head to right size, uses bilinear interpolation by default
scale = cv2.resize(image,(0,0),fx=hs,fy=ws)
#calculate head postion for given values
sxdis = int(xdis*ws) #applying scale to x distance and turning it into a integer
sydis = int(ydis*hs) #applying scale to y distance and turning it into a integer
sycent = sydis+300 #adding half head hight to get center
ystart = sycent-700 #subtract where you want the head center to be in pixels, this is for the vertical
yend = ystart+2500 #Add whatever you want vertical resolution to be
xcent = sxdis+300 #adding half head hight to get center
xstart = xcent-1000 #subtract where you want the head center to be in pixels, this is for the horizontal
xend = xstart+2000 #add whatever you want the horizontal resolution to be
#Crop the image
cropped = scale[ystart:yend, xstart:xend]
Its a mess but it works exactly how I wanted it to work.
ended up going with openCV instead of switching to python-Recognition because of speed but I might switch over if I can get multithreading to work in python-recognition.

Perform blob detection on matrix with openCV in Python

I have captured some data in a 16x8 heatmap matrix called pixels.
I would like to do some blob recognition on this matrix data and display the result on the screen.
I was able to do this in a very convoluted way by displaying the data as an image and saving it to a RAM disk then performing blob recognition:
Display data as an image
get the current figure drawn
save image to RAM disk
detect blobs
display image
It' slow. Is there an easier/shorter way to detect blobs in a matrix? Or at least skipping the ramdisk save? Thank you!
The code:
# Display data as an image. maybe not necessary?
rez = plt.imshow(np.reshape(np.repeat(0,128),(16,8)),cmap=plt.cm.hot,interpolation='hanning')
plt.draw()
plt.pause(0.0005)
# read data
pixels = s.readData()
# update data
rez.set_data(np.reshape(pixels,(16,8)))
# get the current figure drawn
fig1 = plt.gcf()
# save to RAM disk
fig1.savefig('/home/pi/ramdisk/img.png', dpi=300)
# Read image
im0 = cv2.imread("/home/pi/ramdisk/img.png", cv2.IMREAD_COLOR)
im1 = cv2.imread("/home/pi/ramdisk/img.png", cv2.IMREAD_GRAYSCALE)
im = cv2.threshold(im1, 158, 255, cv2.THRESH_BINARY_INV)[1]
params = cv2.SimpleBlobDetector_Params()
params.minArea =50
detector = cv2.SimpleBlobDetector_create(params)
# Detect blobs.
keypoints = detector.detect(im)
# Draw detected blobs
im_with_keypoints = cv2.drawKeypoints(im0, keypoints, np.array([]), (0,255,0), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
#display image with blobs
....

I can't change my RGB colour into grayscale images in python using CV

So, I am doing this project to detect diabetic retinopathy using deep learning. I however am stuck in the preprocessing image section as the pictures that are in different folders(for diff stages of DR) wouldn't convert into grayscale nomatter how much I try.
Here is my functions that does the early preprocessing stage:
def preprocessing(conditionname,directory):
for image in os.listdir(directory):
label = eye_label(conditionname,image)
path = os.path.join(directory,image)
image = cv2.imread(path,cv2.IMREAD_COLOR) #Reading the colour images
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) #Changing coloured image into black and white
#image = cv2.addWeighted(image,10,cv2.GaussianBlur(image , (0,0) , sigma_x) ,-4 ,12)
image = cv2.resize(image,(image_size,image_size)) #Changing the size of each image
return image
Try using your debugger or IDE to check everything gives you the result you expect, one step at a time.
If you load an image, print its shape:
img = cv2.imread(...)
print(image.shape)
If you convert an image to greyscale, check it has 1 channel afterwards:
img = cv2.cvtColor(...)
print(image.shape)
If you resize an image, check its size is what you expect:
img = cv2.resize(...)
print(image.shape)
If you are going to return an image from a function, check its size and type:
print(result.shape, result.dtype)
return result

Unable to focus on the number plate of a truck image, and retrieve it in order to put in a different folder

]3
Kindly ignore that the images of input and output trucks are different. In reality, the output should be the focused number plate of the input image (the entire truck).
I have been trying to detect nameplates from a truck image. I followed instructions from a website, but I am unable to focus on the number plate alone and retrieve it. In the end, I am getting green lines at random places on the truck image. The website tells me to convert the original image into grey scale and many more after which it is supposed to detect the number plate, but it is not happening.
I am new to open CV and just following what a website suggested me to. My goal is to retrieve only the number-plate from the truck image and put it into a different folder.
Suggestions on where I can understand these things would be helpful.
import cv2
import numpy as np
img =
cv2.imread("path")
cv2.namedWindow("Original Image",cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("Original Image",img)
# Display image
# RGB to Gray scale conversion
img_gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
cv2.namedWindow("Gray Converted Image",cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("Gray Converted Image",img_gray)
# Display Image
# Noise removal with iterative bilateral filter(removes noise while preserving edges)
noise_removal = cv2.bilateralFilter(img_gray,9,75,75)
cv2.namedWindow("Noise Removed Image",cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("Noise Removed Image",noise_removal)
# Display Image
# Histogram equalisation for better results
equal_histogram = cv2.equalizeHist(noise_removal)
cv2.namedWindow("After Histogram equalisation",cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("After Histogram equalisation",equal_histogram)
# Display Image
# Morphological opening with a rectangular structure element
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
morph_image = cv2.morphologyEx(equal_histogram,cv2.MORPH_OPEN,kernel,iterations=15)
cv2.namedWindow("Morphological opening",cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("Morphological opening",morph_image)
# Display Image
# Image subtraction(Subtracting the Morphed image from the histogram equalised Image)
sub_morp_image = cv2.subtract(equal_histogram,morph_image)
cv2.namedWindow("Subtraction image", cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("Subtraction image", sub_morp_image)
# Display Image
# Thresholding the image
ret,thresh_image = cv2.threshold(sub_morp_image,0,255,cv2.THRESH_OTSU)
cv2.namedWindow("Image after Thresholding",cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("Image after Thresholding",thresh_image)
# Display Image
# Applying Canny Edge detection
canny_image = cv2.Canny(thresh_image,250,255)
cv2.namedWindow("Image after applying Canny",cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("Image after applying Canny",canny_image)
# Display Image
canny_image = cv2.convertScaleAbs(canny_image)
# dilation to strengthen the edges
kernel = np.ones((3,3), np.uint8)
# Creating the kernel for dilation
dilated_image = cv2.dilate(canny_image,kernel,iterations=1)
cv2.namedWindow("Dilation", cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("Dilation", dilated_image)
# Displaying Image
# Finding Contours in the image based on edges
new,contours, hierarchy = cv2.findContours(dilated_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours= sorted(contours, key = cv2.contourArea, reverse = True)[:10]
# Sort the contours based on area ,so that the number plate will be in top 10 contours
screenCnt = None
# loop over our contours
for c in contours:
# approximate the contour
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.06 * peri, True) # Approximating with 6% error
# if our approximated contour has four points, then
# we can assume that we have found our screen
if len(approx) == 4: # Select the contour with 4 corners
screenCnt = approx
break
final = cv2.drawContours(img, [screenCnt], -1, (0, 255, 0), 3)
# Drawing the selected contour on the original image
cv2.namedWindow("Image with Selected Contour",cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("Image with Selected Contour",final)
# Masking the part other than the number plate
mask = np.zeros(img_gray.shape,np.uint8)
new_image = cv2.drawContours(mask,[screenCnt],0,255,-1,)
new_image = cv2.bitwise_and(img,img,mask=mask)
cv2.namedWindow("Final_image",cv2.WINDOW_NORMAL)
cv2.imshow("Final_image",new_image)
# Histogram equal for enhancing the number plate for further processing
y,cr,cb = cv2.split(cv2.cvtColor(new_image,cv2.COLOR_RGB2YCrCb))
# Converting the image to YCrCb model and splitting the 3 channels
y = cv2.equalizeHist(y)
# Applying histogram equalisation
final_image = cv2.cvtColor(cv2.merge([y,cr,cb]),cv2.COLOR_YCrCb2RGB)
# Merging the 3 channels
cv2.namedWindow("Enhanced Number Plate",cv2.WINDOW_NORMAL)
# Creating a Named window to display image
cv2.imshow("Enhanced Number Plate",final_image)
# Display image
cv2.waitKey() # Wait for a keystroke from the user
l_plate_img = img[screenCnt[0]:screenCnt[1], screenCnt[2]:screenCnt[3]
should return just the part of your image containing the license plate, all further processing can be done on this object.

Categories

Resources