I have recently downloaded some code in python that tries to scan a receipt(or prepare for scanning). I tried to run the code, but there seems to be a problem. Python doesn't recognize the module 'Rect'. I tried to download the module, but there is no such module available. I'm stuck and am wondering what to do.
Note: Only one line of code uses the module
Code :
import cv2
import numpy as np
import rect
# add image here.
image = cv2.imread('test_pic.jpg')
# resize image
# choose optimal dimensions
image = cv2.resize(image, (1500, 880))
# create copy of original image
orig = image.copy()
# convert to grayscale and blur to smooth
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# gaussian blur to smoothen texture
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
#blurred = cv2.medianBlur(gray, 5)
# apply Canny Edge Detection
edged = cv2.Canny(blurred, 0, 50)
orig_edged = edged.copy()
# find the contours in the edged image
# keep only the largest ones, and
# initialize screen contour
(contours, _) = cv2.findContours(edged, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)
#x,y,w,h = cv2.boundingRect(contours[0])
#cv2.rectangle(image,(x,y),(x+w,y+h),(0,0,255),0)
# get approximate contour
for c in contours:
p = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * p, True)
if len(approx) == 4:
target = approx
break
# map target points to 800x800 quadrilateral
approx = rect.rectify(target)
pts2 = np.float32([[0,0],[800,0],[800,800],[0,800]])
M = cv2.getPerspectiveTransform(approx,pts2)
dst = cv2.warpPerspective(orig,M,(800,800))
cv2.drawContours(image, [target], -1, (0, 255, 0), 2)
dst = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
# use thresholding on warped image to get scanned effect (If Required)
ret,th1 = cv2.threshold(dst,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(dst,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(dst,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv2.THRESH_BINARY,11,2)
ret2,th4 = cv2.threshold(dst,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# show results
cv2.imshow("Original.jpg", orig)
cv2.imshow("Original Gray.jpg", gray)
cv2.imshow("Original Blurred.jpg", blurred)
cv2.imshow("Original Edged.jpg", orig_edged)
cv2.imshow("Outline.jpg", image)
cv2.imshow("Thresh Binary.jpg", th1)
cv2.imshow("Thresh mean.jpg", th2)
cv2.imshow("Thresh gauss.jpg", th3)
cv2.imshow("Otsu's.jpg", th4)
cv2.imshow("dst.jpg", dst)
# other thresholding methods
"""
ret,thresh1 = cv2.threshold(dst,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(dst,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(dst,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(dst,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(dst,127,255,cv2.THRESH_TOZERO_INV)
cv2.imshow("Thresh Binary", thresh1)
cv2.imshow("Thresh Binary_INV", thresh2)
cv2.imshow("Thresh Trunch", thresh3)
cv2.imshow("Thresh TOZERO", thresh4)
cv2.imshow("Thresh TOZERO_INV", thresh5)
"""
cv2.waitKey(0)
cv2.destroyAllWindows()
In the github repo you presumably grabbed the code from, there's another file called rect.py with a single function rectify() that is used in the main program. In Python, if you create other .py modules, you can import them into your code for better encapsulation of certain functions, although it seems really unnecessary in this code to keep the rectify() function in a different file altogether. Something that's equally basic but more common is a .py file with all your functions, and then a main .py file which uses those functions.
Edit: so to be clear, the rect module is in the repo itself. A word of advice, generally clone a whole repo unless you know for sure that you don't need the other files in it.
Related
I know the quality is so so bad, but that's original image
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
rectKern = cv2.getStructuringElement(cv2.MORPH_RECT, (85, 64))
blackhat = cv2.morphologyEx(gray, cv2.MORPH_BLACKHAT, rectKern)
edges = cv2.Canny(light, 120, 255, 1)
squareKern = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
light = cv2.morphologyEx(gray, cv2.MORPH_OPEN, squareKern)
light = cv2.threshold(light, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
Here is the result
How can I check if inside that blue rectangle, there are numbers or not? (if there is no number inside, then I won't draw a bounding box around it since it's not license plate).
There are multiple methods for this. Choose depending on your requirement.
1- OCR via pytesseract - crop the rectangular region and then pass it to the tesseract to extract the text from the image.
# Import required packages
import cv2
import pytesseract
# Mention the installed location of Tesseract-OCR in your system
pytesseract.pytesseract.tesseract_cmd = 'System_path_to_tesseract.exe'
# Read image from which text needs to be extracted
img = cv2.imread("sample.jpg")
# Preprocessing the image starts
# Convert the image to gray scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Performing OTSU threshold
ret, thresh1 = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)
# Specify structure shape and kernel size.
# Kernel size increases or decreases the area
# of the rectangle to be detected.
# A smaller value like (10, 10) will detect
# each word instead of a sentence.
rect_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (18, 18))
# Appplying dilation on the threshold image
dilation = cv2.dilate(thresh1, rect_kernel, iterations = 1)
# Finding contours
contours, hierarchy = cv2.findContours(dilation, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_NONE)
# Creating a copy of image
im2 = img.copy()
# A text file is created and flushed
file = open("recognized.txt", "w+")
file.write("")
file.close()
# Looping through the identified contours
# Then rectangular part is cropped and passed on
# to pytesseract for extracting text from it
# Extracted text is then written into the text file
for cnt in contours:
x, y, w, h = cv2.boundingRect(cnt)
# Drawing a rectangle on copied image
rect = cv2.rectangle(im2, (x, y), (x + w, y + h), (0, 255, 0), 2)
# Cropping the text block for giving input to OCR
cropped = im2[y:y + h, x:x + w]
# Open the file in append mode
file = open("recognized.txt", "a")
# Apply OCR on the cropped image
text = pytesseract.image_to_string(cropped)
# Appending the text into file
file.write(text)
file.write("\n")
# Close the file
file.close
Source: Link
2- opencv's EAST text detector - Tutorial
Also, have a look at this question for more methods
And this as well
I'm trying to use Tessract in the code below to extract the two lines of the image. I tryied to improve the image quality but even though it didn't work.
Can anyone help me?
from PIL import Image, ImageEnhance, ImageFilter
import pytesseract
img = Image.open(r'C:\ocr\test00.jpg')
new_size = tuple(4*x for x in img.size)
img = img.resize(new_size, Image.ANTIALIAS)
img.save(r'C:\\test02.jpg', 'JPEG')
print( pytesseract.image_to_string( img ) )
Given the comment by #barny I don't know if this will work, but you can try the code below. I created a script that selects the display area and warps this into a straight image. Next a threshold to a black and white mask of the characters and the result is cleaned up a bit.
Try if it improves recognition. If it does, also look at the intermediate stages so you'll understand all that happens.
Update: It seems Tesseract prefers black text on white background, inverted and dilated the result.
Result:
Updated result:
Code:
import numpy as np
import cv2
# load image
image = cv2.imread('disp.jpg')
# create grayscale
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# perform threshold
retr, mask = cv2.threshold(gray_image, 190, 255, cv2.THRESH_BINARY)
# findcontours
ret, contours, hier = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# select the largest contour
largest_area = 0
for cnt in contours:
if cv2.contourArea(cnt) > largest_area:
cont = cnt
largest_area = cv2.contourArea(cnt)
# find the rectangle (and the cornerpoints of that rectangle) that surrounds the contours / photo
rect = cv2.minAreaRect(cont)
box = cv2.boxPoints(rect)
box = np.int0(box)
#### Warp image to square
# assign cornerpoints of the region of interest
pts1 = np.float32([box[2],box[3],box[1],box[0]])
# provide new coordinates of cornerpoints
pts2 = np.float32([[0,0],[500,0],[0,110],[500,110]])
# determine and apply transformationmatrix
M = cv2.getPerspectiveTransform(pts1,pts2)
tmp = cv2.warpPerspective(image,M,(500,110))
# create grayscale
gray_image2 = cv2.cvtColor(tmp, cv2.COLOR_BGR2GRAY)
# perform threshold
retr, mask2 = cv2.threshold(gray_image2, 160, 255, cv2.THRESH_BINARY_INV)
# remove noise / close gaps
kernel = np.ones((5,5),np.uint8)
result = cv2.morphologyEx(mask2, cv2.MORPH_CLOSE, kernel)
#draw rectangle on original image
cv2.drawContours(image, [box], 0, (255,0,0), 2)
# dilate result to make characters more solid
kernel2 = np.ones((3,3),np.uint8)
result = cv2.dilate(result,kernel2,iterations = 1)
#invert to get black text on white background
result = cv2.bitwise_not(result)
#show image
cv2.imshow("Result", result)
cv2.imshow("Image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
I'm trying to detect this Code128 barcode with Python + zbar module:
(Image download link here).
This works:
import cv2, numpy
import zbar
from PIL import Image
import matplotlib.pyplot as plt
scanner = zbar.ImageScanner()
pil = Image.open("000.jpg").convert('L')
width, height = pil.size
plt.imshow(pil); plt.show()
image = zbar.Image(width, height, 'Y800', pil.tobytes())
result = scanner.scan(image)
for symbol in image:
print symbol.data, symbol.type, symbol.quality, symbol.location, symbol.count, symbol.orientation
but only one point is detected: (596, 210).
If I apply a black and white thresholding:
pil = Image.open("000.jpg").convert('L')
pil = pil .point(lambda x: 0 if x<100 else 255, '1').convert('L')
it's better, and we have 3 points: (596, 210), (482, 211), (596, 212). But it adds one more difficulty (finding the optimal threshold - here 100 - automatically for every new image).
Still, we don't have the 4 corners of the barcode.
Question: how to reliably find the 4 corners of a barcode on an image, with Python? (and maybe OpenCV, or another library?)
Notes:
It is possible, this is a great example (but sadly not open-source as mentioned in the comments):
Object detection, very fast and robust blurry 1D barcode detection for real-time applications
The corners detection seems to be excellent and very fast, even if the barcode is only a small part of the whole image (this is important for me).
Interesting solution: Real-time barcode detection in video with Python and OpenCV but there are limitations of the method (see in the article: the barcode should be close up, etc.) that limit the potential use. Also I'm more looking for a ready-to-use library for this.
Interesting solution 2: Detecting Barcodes in Images with Python and OpenCV but again, it does not seem like a production-ready solution, but more a research in progress. Indeed, I tried their code on this image but the detection does not yield successful result. It has to be noted that it doesn't take any spec of the barcode in consideration for the detection (the fact there's a start/stop symbol, etc.)
import numpy as np
import cv2
image = cv2.imread("000.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gradX = cv2.Sobel(gray, ddepth = cv2.CV_32F, dx = 1, dy = 0, ksize = -1)
gradY = cv2.Sobel(gray, ddepth = cv2.CV_32F, dx = 0, dy = 1, ksize = -1)
gradient = cv2.subtract(gradX, gradY)
gradient = cv2.convertScaleAbs(gradient)
blurred = cv2.blur(gradient, (9, 9))
(_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
closed = cv2.erode(closed, None, iterations = 4)
closed = cv2.dilate(closed, None, iterations = 4)
(_, cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
rect = cv2.minAreaRect(c)
box = np.int0(cv2.boxPoints(rect))
cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
cv2.imshow("Image", image)
cv2.waitKey(0)
Solution 2 is pretty good. The critical factor that made it fail on your image was the thresholding. If you drop the parameter 225 way down to 55, you'll get much better results.
I've reworked the code, making some tweaks here and there. The original code is fine if you prefer. The documentation for OpenCV is quite good, and there are very good Python tutorials.
import numpy as np
import cv2
image = cv2.imread("barcode.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# equalize lighting
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
gray = clahe.apply(gray)
# edge enhancement
edge_enh = cv2.Laplacian(gray, ddepth = cv2.CV_8U,
ksize = 3, scale = 1, delta = 0)
cv2.imshow("Edges", edge_enh)
cv2.waitKey(0)
retval = cv2.imwrite("edge_enh.jpg", edge_enh)
# bilateral blur, which keeps edges
blurred = cv2.bilateralFilter(edge_enh, 13, 50, 50)
# use simple thresholding. adaptive thresholding might be more robust
(_, thresh) = cv2.threshold(blurred, 55, 255, cv2.THRESH_BINARY)
cv2.imshow("Thresholded", thresh)
cv2.waitKey(0)
retval = cv2.imwrite("thresh.jpg", thresh)
# do some morphology to isolate just the barcode blob
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 9))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
closed = cv2.erode(closed, None, iterations = 4)
closed = cv2.dilate(closed, None, iterations = 4)
cv2.imshow("After morphology", closed)
cv2.waitKey(0)
retval = cv2.imwrite("closed.jpg", closed)
# find contours left in the image
(_, cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
rect = cv2.minAreaRect(c)
box = np.int0(cv2.boxPoints(rect))
cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
print(box)
cv2.imshow("found barcode", image)
cv2.waitKey(0)
retval = cv2.imwrite("found.jpg", image)
edge.jpg
thresh.jpg
closed.jpg
found.jpg
output from console:
[[596 249]
[470 213]
[482 172]
[608 209]]
For the following to work, you need to have contrib package installed using pip install opencv-contrib-python
Your OpenCV version would now have a separate class for detecting barcodes.
cv2.barcode_BarcodeDetector() comes equipped with 3 in-built functions:
decode(): returns decoded information and type
detect(): returns the 4 corner points enclosing each detected barcode
detectAndDecode(): returns all the above
Sample Image used is from pyimagesearch blog:
The 4 corners are captured in points.
Code:
img = cv2.imread('barcode.jpg')
barcode_detector = cv2.barcode_BarcodeDetector()
# 'retval' is boolean mentioning whether barcode has been detected or not
retval, decoded_info, decoded_type, points = barcode_detector.detectAndDecode(img)
# copy of original image
img2 = img.copy()
# proceed further only if at least one barcode is detected:
if retval:
points = points.astype(np.int)
for i, point in enumerate(points):
img2 = cv2.drawContours(img2,[point],0,(0, 255, 0),2)
# uncomment the following to print decoded information
#x1, y1 = point[1]
#y1 = y1 - 10
#cv2.putText(img2, decoded_info[i], (x1, y1), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 3, 2)
Result:
Detected barcode:
Detected barcode and information:
One solution not discussed here is PyZbar.
It is helpful to know there are a number of different types of barcode so reading this can be helpful. Now each solution for decoding might have limitations for the types it can decode. #Jeru Luke's solution seems to be only support EAN-13 barcodes currently see docs here.
Now using PyZbar a simple solution for getting the rect object (4 corners) with the decoding and the bonus of finding out which type the barcode it is can be done with this script.
Using this barcode
import cv2
from pyzbar.pyzbar import decode
file_path = r'c:\my_file'
img = cv2.imread(file_path)
detectedBarcodes = decode(img)
for barcode in detectedBarcodes:
(x, y, w, h) = barcode.rect
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 5)
print(barcode.rect)
print(barcode.data)
print(barcode.type)
output
Rect(left=77, top=1, width=665, height=516)
b'9771234567003'
EAN13
Using #Jeru Luke's code you can drawContours and putText.
ZBar supports
EAN-13/UPC-A,
UPC-E, EAN-8,
Code 128,
Code 93,
Code 39,
Codabar,
Interleaved 2 of 5,
QR Code
SQ Code.
So I think PyZbar will also support these types.
Running this python code on the Raspery Pi will cause the pi to become unstable after a few hours. I think there is a memory leak or some resource not being freed. I'm very new to python.
#initialise pygame
pygame.init()
pygame.camera.init()
cam = pygame.camera.Camera("/dev/video0",(width,height))
cam.start()
....
# Read the image we have presaved as an alert image
# and convert it to greyscale and blur it
alertimage = cv2.imread('./alert/alert.jpg')
alertgray = cv2.cvtColor(alertimage, cv2.COLOR_RGBA2GRAY)
alertgray = cv2.GaussianBlur(alertgray, (21, 21), 0)
# Compare a given image to the saved image to and return true if
# they are the same
def IsAlert( image ):
global alertgray
gray = cv2.cvtColor(image, cv2.COLOR_RGBA2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
frameDelta = cv2.absdiff(alertgray, gray)
thresh = cv2.threshold(frameDelta, 40, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.dilate(thresh, None, iterations=2)
(_, cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# loop over the contours
for c in cnts:
# if the contour is large enough
if cv2.contourArea(c) > 1600:
return 0
return 1
# Main loop ####################################################
while True:
# Get an image from tpygame and save it to ram disk
# im doing this beacuse I can't figure our how to convert
# pygame image to cv2 image so I save it and read it back
imageS = cam.get_image()
pygame.image.save(imageS,'/var/ramdsk/picture.jpg')
# Read the image I just saved
image = cv2.imread('/var/ramdsk/picture.jpg')
# Compare the image to a standard image that I have presaved
alert = IsAlert( image )
# Convert the image to grey and blur it
gray = cv2.cvtColor(image, cv2.COLOR_RGBA2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
if lastgray is None:
lastgray = gray
# See what has changed...
frameDelta = cv2.absdiff(lastgray, gray)
thresh = cv2.threshold(frameDelta, 40, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.dilate(thresh, None, iterations=2)
(_, cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# loop over the contours
waschange = change
for c in cnts:
# if the contour is large enough
if cv2.contourArea(c) > 1600:
print "Area: ",cv2.contourArea(c)
change = change + 1
same = 0
break
# If the image is
if change == waschange:
same = same + 1
# If the image has settled after changing then it's time to
# capture it by moving the saved version to another directory
if (change > 0 and same > 3) or init == 0:
fileout = '/home/pi/Desktop/CamManager/clips_new/0x{}L-{}-{}.jpg'.format(mac,t,alert)
shutil.move('/var/ramdsk/picture.jpg',fileout)
change = 0
same = 0
init = 1
print "Saving New Still",fileout
lastgray = gray
cam.stop()
In a similar script I solved a problem with frame.truncate(0)
camera = picamera.PiCamera()
....
camera.capture(frame, format='bgr', use_video_port=True)
....
frame.truncate(0)
Sorry for posting so much code but I am not exactly sure where the resource leak is. After a few hours I can not open a new shell on the pi and I think it's because there aren't enough resources.
You can pinpoint/check memory leaks yourself, using the following tools:
The first tool to use is guppy/heapy - which will track all objects
inside Python's memory
For long-running systems, use dowser - which allows live
objects introspection
RAM usage is demystified with memory_profiler
See my presentation.
BTW, SO has quite a few entries explaining how to use above tools to track memory leaks (GIYF).
I was taking source code from pyimagesearch.com to make a mobile document scanner and tried to test out the code. The edge detection part works but whenever I arrive at the part where it tries to find contours of an image, the program outputs an error saying that there are too many values to unpack, despite the programming working on the author's side.
What's the problem and how do I fix it?
Blog Post about the source code:
http://www.pyimagesearch.com/2014/09/01/build-kick-ass-mobile-document-scanner-just-5-minutes/?__vid=c35c22a06af30132982122000b2a88d7
Youtube video about the program:
https://www.youtube.com/watch?v=yRer1GC2298
Terminal Command in Ubuntu
python scan.py --image images/page.jpg
Result:
STEP 1: Edge Detection
Traceback (most recent call last):
File "scan.py", line 40, in <module>
(cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
ValueError: too many values to unpack
Code:
# USAGE
# python scan.py --image images/page.jpg
# import the necessary packages
from pyimagesearch.transform import four_point_transform
from pyimagesearch import imutils
from skimage.filter import threshold_adaptive
import numpy as np
import argparse
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True,
help = "Path to the image to be scanned")
args = vars(ap.parse_args())
# load the image and compute the ratio of the old height
# to the new height, clone it, and resize it
image = cv2.imread(args["image"])
ratio = image.shape[0] / 500.0
orig = image.copy()
image = imutils.resize(image, height = 500)
# convert the image to grayscale, blur it, and find edges
# in the image
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 75, 200)
# show the original image and the edge detected image
print "STEP 1: Edge Detection"
cv2.imshow("Image", image)
cv2.imshow("Edged", edged)
cv2.waitKey(0)
cv2.destroyAllWindows()
# find the contours in the edged image, kee
(cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_LIST, ping only the
# largest ones, and initialize the screen contourcv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
# loop over the contours
for c in cnts:
# approximate the contour
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# if our approximated contour has four points, then we
# can assume that we have found our screen
if len(approx) == 4:
screenCnt = approx
break
# show the contour (outline) of the piece of paper
print "STEP 2: Find contours of paper"
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
cv2.imshow("Outline", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# apply the four point transform to obtain a top-down
# view of the original image
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
# convert the warped image to grayscale, then threshold it
# to give it that 'black and white' paper effect
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
warped = threshold_adaptive(warped, 250, offset = 10)
warped = warped.astype("uint8") * 255
# show the original and scanned images
print "STEP 3: Apply perspective transform"
cv2.imshow("Original", imutils.resize(orig, height = 650))
cv2.imshow("Scanned", imutils.resize(warped, height = 650))
cv2.waitKey(0)
This is the answer at least works for me. The function return 3 values so:
_,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
(_,cnts,hierarchy) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
In OpenCV 3.0.0 (beta) they have added a return value. This works:
derp,contours,hierarchy = cv2.findContours(dilation.copy(),cv2.RETR_LIST ,cv2.CHAIN_APPROX_SIMPLE)
I have no idea what derp is and it can be ignored.