Rasperry Pi handwriting recognition - python

I'm trying to make a handwriting recognition system using Raspberry Pi.My code detects the text but doesn't print it to screen.When I run the code,the img file detects the handwritings as they appear with blue borders.Another interesting thing is that it detects only in presence of source of light,I mean it's daytime and the environment isn't dark.When I don't turn on the light,the test1.jpg file is completely dark and handwritings aren't detected(I think this topic is about the camera I use or my environment isn't illuminated enough).
I'm doing something wrong but couldn't figure it out.
I'm newby to programming.I hope that someone explains me these stuffs.
Can you help me?
Here is my code.
from picamera import PiCamera
import cv2
import pytesseract
from PIL import Image
from time import sleep
from picamera.array import PiRGBArray
import numpy as np
print ("Capturing Image")
camera = PiCamera()
camera.resolution = (640, 480)
camera.brightness = 50
camera.contrast = 70
camera.framerate = 30
rawCapture = PiRGBArray(camera, size=(640, 480))
camera.capture('/home/pi/Desktop/Photos/test1.jpg')
print("Captured")
sleep(1)
print("Wait, Processing")
img = cv2.imread('/home/pi/Desktop/Photos/test1.jpg', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
items = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = items[0] if len(items) == 2 else items[1]
base = np.zeros(thresh.shape, dtype=np.uint8)
base = cv2.bitwise_not(base)
max_area = 0
for i in range(len(contours)):
x, y, w, h = cv2.boundingRect(contours[i])
ratio = h / w
area = cv2.contourArea(contours[i])
cv2.drawContours(img, [contours[i]], 0, (255, 0, 0), 2)
if 1 < ratio < 3:
max_area = max(area, max_area)
#print("area: " + str(area) + ", max area: " + str(max_area) + ", ratio: " + str(ratio))
# if 1000 < area < max_area / 2:
if 1000 < area < 40000:
mask = np.zeros(thresh.shape, dtype=np.uint8)
cv2.drawContours(mask, [contours[i]], -1, color=255, thickness=-1)
mean = cv2.mean(thresh, mask=mask)
segment = np.zeros((h, w), dtype=np.uint8)
segment[:h, :w] = thresh[y:y + h, x:x + w]
if mean[0] > 150:
# white, invert
segment = cv2.bitwise_not(segment)
base[y:y + h, x:x + w] = segment[:h, :w]
cv2.imshow("base", base)
cv2.drawContours(img, [contours[i]], 0, (255, 0, 0), 2)
cv2.waitKey(0)
custom_config = r'-l eng --oem 3 --psm 6 -c tessedit_char_whitelist="ABCDEFGHIJKLMNOPQRSTUVWXYZ " '
text = pytesseract.image_to_string(base, config=custom_config)
print (text)
cv2.imshow("img", img)
cv2.imshow("base", base)
cv2.waitKey(0)
cv2.destroyAllWindows()
I think there's something wrong with the pytesseract.image_to_string(base, config=custom_config) part.
By the way I'm using raspberry pi 4 2 gb,32 bit os and python 3.7.My camera is v1.3

Related

Detecting and ignoring rectangles that fall under another rectangle and efficient cropping

I am working on a project where I take a floor plan image as input that contains 2-3 floor plans and I need to detect each floorplan and crop them and save in as a different file.
Following are the sample input and output images.
Input:
Output:
So as you can see the second output is wrongly cropped. Also I get smaller rectangles (which are part of the output images) as byproducts.
Following is the code that I am using:
import cv2
import download_imgs_R1
import floorplan_threshold_R2
import pandas as pd
import os
filename = 'project_image.csv'
df = pd.read_csv(filename)
pids = df['id']
urls = df['complete_url']
for pid,url in zip(pids,urls):
name = url.split('/')[-1]
ext = name.split('.')[-1]
filepath = './xxxx/{}/original_images/'.format(pid)
savepath = './xxxx/{}/processed_images/'.format(pid)
savename = name.split('.')[0]
save = savepath+savename+'{}.png'
if ext == 'pdf':
image_name = download_imgs_R1.extract_from_pdf(filename=name, dest=filepath)
else:
image_name = filepath+name
print(image_name)
no_padding_image, crop_img_name = floorplan_threshold_R2.remove_white_space(image_name)
feature_dict = floorplan_threshold_R2.get_img_features(no_padding_image)
cont, hier = floorplan_threshold_R2.contour_method(no_padding_image)
area_dict = floorplan_threshold_R2.max_rect(cont)
roi_area = []
print(feature_dict)
img_area = feature_dict['area']
for area in area_dict:
if area >= img_area*0.1 and area < img_area:
roi_area.append(area)
plan_no = 1
for a in roi_area:
plan = area_dict[a]
# del area_dict[a]
x,y,w,h = plan
aspect_ratio = h/w
if x <=50 or y <= 25:
roi = no_padding_image[y:y+h, x:x+w]
else:
roi = no_padding_image[y-50:y+h+10, x-20:x+w+10]
print('PID: {}, No. {}'.format(pid,plan_no))
# cv2.rectangle(no_padding_image, (x-10,y-10), (x+w+10, y+h+10), (255,255,255), 2)
# roi = cv2.copyMakeBorder(roi, 10, 10, 10, 10, cv2.BORDER_CONSTANT, None, value = [255,255,255])
# cv2.imshow('ROI-{}'.format(image_name),roi)
cv2.imwrite(save.format(plan_no),roi)
cv2.waitKey(0)
plan_no += 1
floor_plan_threshold_R2.py:
import cv2
from cv2 import dilate
from cv2 import findContours
import imutils
import numpy as np
import download_imgs_R1
def remove_white_space(filename:str):
savename = filename
img = cv2.imread(filename=filename)
orignal = img.copy()
gray = cv2.cvtColor(orignal, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (25,25), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Perform morph operations, first open to remove noise, then close to combine
noise_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, noise_kernel, iterations=2)
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, close_kernel, iterations=3)
# Find enclosing boundingbox and crop ROI
coords = cv2.findNonZero(close)
x,y,w,h = cv2.boundingRect(coords)
# cv2.rectangle(orignal, (x, y), (x + w, y + h), (36,255,12), 2)
if x <= 50 or y <= 10:
crop = orignal[y:y+h, x:x+w]
else:
crop = orignal[y-10:y+h+10, x-60:x+w+10]
cv2.imwrite(savename,crop)
# cv2.imshow('Removed White space (Preprocess - 1)',crop)
cv2.waitKey(0)
return crop, savename
def get_img_features(image, filename:str=None,resize:bool=False):
if not filename:
res = image.copy()
else:
res = cv2.imread(filename)
img_height, img_width, img_channel = image.shape
if resize is True and image.shape[0] > 800:
res = imutils.resize(res, height=720)
img_height, img_width, img_channel = res.shape
img_area = img_width * img_height
img_aspect_ratio = img_width/img_height
img_features = {'height':img_height, 'width':img_width, 'area':img_area, 'aspect_ratio':img_aspect_ratio}
return img_features
def mask_method(image, filename:str=None):
if not filename:
res = image.copy()
else:
res = cv2.imread(filename)
hsv_plan = cv2.cvtColor(res, cv2.COLOR_BGR2HSV)
#define range for blue color (HSV Range)
blue_min = np.array([14,100,76])
blue_max = np.array([130,255,255])
bluemask = cv2.inRange(hsv_plan,blue_min,blue_max)
blue_output = cv2.bitwise_and(hsv_plan, hsv_plan, mask=bluemask)
grey_mask = cv2.cvtColor(blue_output, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(grey_mask, 100, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
kernel = np.ones((3,3), np.uint8)
dil = dilate(thresh, kernel, iterations=2)
cont,hier = findContours(dil, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
return cont, hier
def contour_method(image, filename:str=None):
if not filename:
res = image.copy()
else:
res = cv2.imread(filename)
grey_plan = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
ret2, thresh2 = cv2.threshold(grey_plan, 160, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((3,3), np.uint8)
dil_grey = dilate(thresh2, kernel, iterations=2)
cont,hier = findContours(dil_grey, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
return cont,hier
def max_rect(cntrs):
ar = {}
for cnt in cntrs:
x,y,w,h = cv2.boundingRect(cnt)
area = w*h
ar[area] = (x,y,w,h)
return ar
I need to find a generic solution for cropping the image as just providing a number for cropping will affect other images as well.

How to remove shadow of moving object from image using opencv (python)?

I am trying to do background subtraction using MOG2, It was working fine, but when there is deep shadow of a moving object then the shadow is considered as foreground object and I don't want that shadow as foreground object (I'm running MOG2 for 13 images). How can I remove these shadow so that it does not come in foreground?
Here is a sample image...
original img
image after applying MOG2
here is my sample code...
import os
import numpy as np
import cv2
import glob
import imutils
i=0
bg_flag = 0
image_list = []
bgs_list = []
#bgsfinal function
def detection(image_list):
global i
global bg_flag
bgs3_img = None
backsub = cv2.createBackgroundSubtractorMOG2(128, cv2.THRESH_BINARY, 1)
print("start2")
for k in range(len(image_list)):
frame = image_list[k]
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imwrite('./gray/'+str(k)+'.jpg', frame)
#blur = cv2.medianBlur(frame, 21)
blur = frame
bgs_list.append(blur)
for bg in range(len(bgs_list)):
rects = []
#start_time = time.time()
frame_blur = bgs_list[bg]
img = image_list[bg].copy()
s_frame = image_list[bg]
new_frame = s_frame.copy()
fgmask = backsub.apply(frame_blur)
cv2.imwrite("./bgs/"+str(i)+".jpg", fgmask)
fgmask[fgmask==127] = 0
cv2.imwrite("./dilate/"+str(i)+".jpg", fgmask)
thresh = cv2.threshold(fgmask, 128, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.erode(thresh, None, iterations = 1)
thresh = cv2.dilate(thresh, None, iterations=1)
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
for c in cnts:
#M = cv2.moments(c)
A = cv2.contourArea(c)
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(new_frame, (x, y), (x + w, y + h), (0,0, 255), 1)
cv2.putText(new_frame, str(A), (x - 10, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
cv2.imwrite("./area/"+str(i)+".jpg", new_frame)
cv2.rectangle(thresh, (x, y), (x + w, y + h), (255,255, 255), 1)
cv2.putText(thresh, str(A), (x - 10, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
cv2.imwrite("./area_bgs/"+str(i)+".jpg", thresh)
i+=1
print("Done!")
#this folder contains 13 continuous images
images = glob.glob('./inci4/*.jpg')
for j in range(len(images)):
img = cv2.imread(images[j])
img = cv2.resize(img, (360, 640))
image_list.append(img)
detection(image_list)

Unable to clip and save the ROI/bounding box in opencv python

Im trying to save only the rectangular ROI region from a video file into images. But the entire image is getting saved with the RED rectangular ROI box on it. What am I doing wrong here ?
I tried saving rect_img but thats giving error "!_img.empty() in function 'imwrite'" ,
and not saving any images at all.
The upper_left and bottom_right coordinates are for a 1920 X 1080p video, you wil have to adjust is as per your video resolution.
import cv2
from matplotlib import pyplot as plt
import imutils
import numpy as np
import pytesseract
cam_capture = cv2.VideoCapture('1080_EDIT.webm')
upper_left = (1400, 700)
bottom_right = (700, 1000)
ctr=1 #filename counter
while True:
_, image_frame = cam_capture.read()
ctr+=1
#Rectangle marker
r = cv2.rectangle(image_frame, upper_left, bottom_right, (100, 50, 200), 5)
rect_img = image_frame[upper_left[1] : bottom_right[1], upper_left[0] : bottom_right[0]]
cv2.imwrite("rect"+str(ctr)+".jpg",r)
#print (rect_img)
#img=cv2.imread(rect_img)
gray = cv2.cvtColor(r, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 13, 15, 15)
edged = cv2.Canny(gray, 30, 200)
contours = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(contours)
contours = sorted(contours, key = cv2.contourArea, reverse = True)[:10]
screenCnt = None
for c in contours:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.018 * peri, True)
if len(approx) == 4:
screenCnt = approx
break
if screenCnt is None:
detected = 0
print ("No contour detected")
else:
detected = 1
if detected == 1:
cv2.drawContours(r, [screenCnt], -1, (0, 0, 255), 3)
cv2.imshow("image", image_frame)
if cv2.waitKey(1) % 256 == 27 :
break
cam_capture.release()
cv2.destroyAllWindows()
Solved it by
roi=r[700:1000,700:1400]
cv2.imwrite("rect"+str(ctr)+".jpg",roi)

Using RaspberryPi 3 with Pi-Camera and OpenCV to do PeopleCounting From the Top

I have been stuck for sometime now. Does anyone know of any links that can help me with using
(Hardware)- Raspberry Pi 3 connected to a Pi Cam NOT webcam
Then using both hardware mentioned above i wan to use any available software I'm guessing openCV to do people counting from the top.
Example Video: https://www.youtube.com/watch?v=BszUJXLR2oA
Almost all available examples using the raspberry pi to do people counting from the top doesnt use the picam.. webcams are big and bulky. So if there is any tutorial or what available please help. Thank You
==========================================================================
What i tried:
So the problem I'm having is i have a sample code that uses openCV with a webcam.. instructions can be found here :https://www.hackster.io/deligence-technologies/person-counting-system-using-opencv-and-python-faf14f
And in this code it uses a usb webcam thus the line that i commented that says "#HERE i need to use the pi cam instead" that line is using cv2.VideoCapture(0).. i need to know how to use the picam instead. any ideas?
import argparse
import datetime
import imutils
import math
import cv2
import numpy as np
width = 800
textIn = 0
textOut = 0
def testIntersectionIn(x, y):
res = -450 * x + 400 * y + 157500
if((res >= -550) and (res < 550)):
print (str(res))
return True
return False
def testIntersectionOut(x, y):
res = -450 * x + 400 * y + 180000
if ((res >= -550) and (res <= 550)):
print (str(res))
return True
return False
camera = cv2.VideoCapture(0) #HERE i need to use the pi cam instead
firstFrame = None
while True:
(grabbed, frame) = camera.read()
text = "Unoccupied"
if not grabbed:
break
frame = imutils.resize(frame, width=width)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
if firstFrame is None:
firstFrame = gray
continue
frameDelta = cv2.absdiff(firstFrame, gray)
thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.dilate(thresh, None, iterations=2)
_, cnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in cnts:
if cv2.contourArea(c) < 12000:
continue
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.line(frame, (width / 2, 0), (width, 450), (250, 0, 1), 2) #blue line
cv2.line(frame, (width / 2 - 50, 0), (width - 50, 450), (0, 0, 255), 2)#red line
rectagleCenterPont = ((x + x + w) /2, (y + y + h) /2)
cv2.circle(frame, rectagleCenterPont, 1, (0, 0, 255), 5)
if(testIntersectionIn((x + x + w) / 2, (y + y + h) / 2)):
textIn += 1
if(testIntersectionOut((x + x + w) / 2, (y + y + h) / 2)):
textOut += 1
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.putText(frame, "In: {}".format(str(textIn)), (10, 50),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
cv2.putText(frame, "Out: {}".format(str(textOut)), (10, 70),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
cv2.putText(frame, datetime.datetime.now().strftime("%A %d %B %Y %I:%M:%S%p"),
(10, frame.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255), 1)
cv2.imshow("Security Feed", frame)
camera.release()
cv2.destroyAllWindows()
You say you read the link I posted in my comment but that is obviously not the case.
For clarity, this tutorial shows you how to do what you want to do and you need to read the code in the article and bring that into your code base.
What you are trying to do in your code is open the first USB webcam attached to your raspberry Pi. You do that on this line here:
camera = cv2.VideoCapture(0) #HERE i need to use the pi cam instead
As your comment does indeed state.
What you need to do is instead use the PiCamera library, like this:
# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
rawCapture = PiRGBArray(camera)
# allow the camera to warmup
time.sleep(0.1)
# grab an image from the camera
camera.capture(rawCapture, format="bgr")
image = rawCapture.array
# display the image on screen and wait for a keypress
cv2.imshow("Image", image)
cv2.waitKey(0)
The above example and tutorial should get you up and running with the basics, you can then modify the Hackster tutorial that you are following to use the PiCamera instead.

How to trace a path generated by openCV findContours() using ReportLab PDFgen?

Im working with openCV for a project that traces patterns and allows me to manipulate that pattern as a path in Adobe Illustrator with the image of the pattern in the background.
Below is the solution that I and a friend have come up with.
The output of drawContours() doesn't match the vector path I am creating with PDFgen.
drawContours() output has a blue stroke
generated path has black stroke
My source code is below.
How can I trace a path generated by findContours() using ReportLab PDFgen?
import numpy as np
import cv2
import math
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
print(cv2.__version__)
im = cv2.imread('img.jpg')
#Orient the image properly
# grab the dimensions of the image and calculate the center
# of the image
(h, w) = im.shape[:2]
center = (w / 2, h / 2)
# rotate the image by 180 degrees
M = cv2.getRotationMatrix2D(center, 180, 1.0)
rotated = cv2.warpAffine(im, M, (w, h))
#flip the image across
flippedColor = cv2.flip(rotated, 1) #used to display the result of drawContours in color
imgray = cv2.cvtColor(rotated, cv2.COLOR_BGR2GRAY)
blur = cv2.flip(imgray, 1)
#thresholding
(thresh, binRed) = cv2.threshold(blur, 200, 255, cv2.THRESH_BINARY)
_, Rcontours, hier_r = cv2.findContours(binRed,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE)
r_areas = [cv2.contourArea(c) for c in Rcontours]
max_rarea = np.argmax(r_areas)
CntExternalMask = np.ones(binRed.shape[:2], dtype="uint8") * 255
contourMax= Rcontours[max_rarea]
# calc arclentgh
arclen = cv2.arcLength(contourMax, True)
# approx the contour
epsilon = arclen * 0.0005
contour = cv2.approxPolyDP(contourMax, epsilon, True)
cv2.drawContours(flippedColor,[contour],-1,(255,0,0),1)
'''
#display the image for testing
cv2.imshow('image',flippedColor)
cv2.waitKey(0)
cv2.destroyAllWindows()
'''
#set up the pdf with proper size and stuff
canvas = canvas.Canvas("output.pdf", pagesize=letter)
canvas.bottomup = 1
canvas.setLineWidth(0.1)
h,w = im.shape[:2]
canvas.setPageSize((h, w))
canvas.drawImage("img.jpg", 0, 0)
#draw the path
last_angle = 0
last_angle1 = 0
p1 = contour[0][0]
ccount = 0
pathman = canvas.beginPath()
for index,p in enumerate(contour):
if index==len(contour)-1:
break
s1 = contour[index+1][0]
p = p[0]
dist1 = get_dist(p1,p)
dist2 = get_dist(s1,p)
dist = get_dist(s1,p1)
ccount+=1
cv2.circle(CntExternalMask, (p[0], p[1]), 5, (0,255,0), -1)
cv2.circle(CntExternalMask, (p1[0], p1[1]), 5, (0,255,0), -1)
cv2.line(CntExternalMask, (p[0], p[1]), (p1[0], p1[1]), (100, 200, 0), 5)
pathman.moveTo(p[0],p[1])
pathman.lineTo(p[0],p[1])
canvas.line(p[0], p[1],p1[0], p1[1])
p1 = p
p = contour[0][0]
cv2.line(CntExternalMask, (p[0], p[1]), (p1[0], p1[1]), (100, 200, 0), 5)
print ("count = ",ccount)
canvas.line(p[0], p[1],p1[0], p1[1])
canvas.drawPath(pathman, fill=1, stroke=1)
canvas.save()
#save image
cv2.imwrite("output.jpg", CntExternalMask)
cv2.waitKey(0)
cv2.destroyAllWindows()

Categories