How do I decode partially obscured QR codes? - python

I have a library of hundreds of pictures from which I need to extract information encoded in a QR code in each picture.
For 70% of the pictures, pyzbar simply works. For more difficult cases, I try non-linear binarization of the image as suggested by this post: https://stackoverflow.com/a/61443430/1579211
This gets me another 15-20% of the way.
But for about 10% of the images this fails:
from PIL import Image
from pyzbar.pyzbar import decode, ZBarSymbol
from kraken.binarization import nlbin
def read_QRcode(image):
codes = decode(image, symbols=[ZBarSymbol.QRCODE])
if not codes:
codes = decode(nlbin(image), symbols=[ZBarSymbol.QRCODE])
if not codes:
raise RuntimeError(
f'Could not decode a QR code from {image.filename}...'
)
return codes
image = Image.open('sample.jpg')
read_QRcode(image)
When I open up these images (attached sample.jpg) on the screen, my phone, which has a QR scanner built into the camera app, can decode this QR code correctly (see attached screenshot or try yourself).
Does anyone feel up-to the challenge to help me figure this out?

Related

Issue with QR Code reading with OpenCV or Pyzbar

I'm trying to decode a QR Code using Python, or any other language to be honest. I am also familiar with Javascript or PHP, but Python seemed to be the most appropriate one for this task.
This is part of a bigger piece of code that I am writing for a little challenge. I need to extract a password from the QR Code. I've tried using a QR Code reader on my phone and I can get the password so I can confirm that there is no issue with the QR Code itself.
Here is the QRCode:
And the string to retrieve is "The key is /qrcod_OMevpf".
So far I've tried using two different python libraries. Open CV and Pyzbar, with the following codes:
OpenCV
image = cv2.imread(imgAbsolutePath)
qrCodeDetector = cv2.QRCodeDetector()
decodedText, points, _ = qrCodeDetector.detectAndDecode(image)
if points is not None:
# QR Code detected handling code
print("QR code detected")
print(decodedText)
else:
print("QR code not detected")
Which prints "QR code detected" and then an empty string.
Pyzbar
qr = decode(Image.open('result.png'), symbols=[ZBarSymbol.QRCODE])
print(qr)
Which prints "[]"
Do you know why these don't work or can you suggest any other libraries that works ?
Thanks
I finally got it to work using zxing :
from zxing import BarCodeReader
def decode_qr_code(image_path):
reader = BarCodeReader()
barcode = reader.decode(image_path)
return barcode.parsed
qr_code = decode_qr_code("result.png")
print(qr_code)

OpenCV not detecting QR code in the image

I have been trying to detect and decode QR codes from captured images through phone. I have been facing trouble to decode picture a as the script is failing to detect there is QR code here. However, if I crop just the QR code as in picture c the script is able to decode the code. What modification do I need to make in the script to make it work in picture a?`
import cv2
from pyzbar.pyzbar import decode
from pyzbar.pyzbar import ZBarSymbol
image_path = "Test_Image.png"
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
blur = cv2.GaussianBlur(img, (5, 5), 0)
ret, bw_im = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
code = decode(bw_im, symbols=[ZBarSymbol.QRCODE])
print (code)
for barcode in decode (bw_im, symbols=[ZBarSymbol.QRCODE]):
print (barcode.data)
print (barcode.rect)
myData = barcode.data.decode ('utf-8')
print (myData)
break
This should probably be renamed to "Pyzbar not detecting QR code in the image" since you are just using OpenCV for loading the image/image processing.
Regardless, I have run into a similar issue as you, and I think the limitation is that opencv and pyzbar perform worse the smaller the QR code is relative to the entire image.
In my case, I already had some bounding boxes around the objects that had the QR code on them so I just search within the bounding box, and the smaller search area improves detection/decoding.
Depending on your efficiency requirements, you could try to do a coarser search, finding certain shapes in the image or objects that have a certain color and then use the QR search in those regions of interest. If you need to do real-time processing or keep computational overhead low then this may not be feasible.
You could also just apply some default cropping to your image, which won't be very robust if your QR code is going to be moving around, but would reduce the search area and improve the detection/decoding.
As far as I have been able to experiment, both pyzbar and OpenCV perform pretty well for decoding, but they have some problems with detecting difficult QRs. You could try QReader for your use case. It uses pyzbar, sweetened with some image preprocessing fallbacks, on the decoding side, so the decoding performance will be quite similar to the one you are using now. However, for the detection part, it uses a YoloV7 based QR detector that heavily increases the detection rate on difficult images.
from qreader import QReader
import cv2
image_path = "Test_Image.png"
# Create a QReader instance
qreader = QReader()
# Get the image (as RGB)
image = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)
# Use the detect_and_decode function to get the decoded QR data
decoded_texts = qreader.detect_and_decode(image=image)
# Print the results
for text in decoded_texts:
print(text)

Why is PIL.UnidentifiedImageError being raised when trying to open an image from an io.bytesIO object?

In short terms, when trying to open an image using byte data, I unfortunately end up with an error. Here is some of the code for more clarity.
test2.py:
logo = b"iVBORw0KGgoAAAA ... "
#(It's 60k characters long don't worry about it)
test.py:
import test2 as pim
import io
from PIL import Image, ImageTk
sol = io.BytesIO(pim.logo)
image = Image.open(sol)
Apparenly for some strange reason, I end up with this error:
PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x0000028D819373D0>
I've tried searching on other posts. I found some similar ones, but none of the solutions worked.
#martineau actually answered the question but here is a quick runup:
Convert base64 data, use it in a bytesio class and put it into an image:
s = base64.b64decode(pim.logo)
sol = io.BytesIO(s)
image = Image.open(sol)

How to get the x, y position of a detected QR code on an image with zbar?

I encoded the number 1639 in the two QR codes of the image below (downloadable here). I printed it, took a photo and tried to detect it:
import zbar
from PIL import Image
scanner = zbar.ImageScanner()
pil = Image.open('20180520_170027_2.jpg').convert('L')
width, height = pil.size
raw = pil.tobytes()
image = zbar.Image(width, height, 'Y800', raw)
result = scanner.scan(image)
for symbol in image:
print symbol.data.decode(u'utf-8') # 1639
It works, even if the size of the QR code is small (~1x1 cm), which is great!
Question: how to get the x, y position of the corners of the QR codes?
It's sure that zbar has this information internally (mandatory to be able to decode the QR code!), but how to get access to it?
Note: here is how to install zbar on Windows and Python 2.7
As suggested by a hint in a comment,
print(symbol.location)
gives the coordinates.
It looks like the zbar::Symbol class in the C++ docs of zlib has the methods get_location_x(), get_location_y() and get_location_size(), so your intuition that this data exists underneath was right.
Coming back to Python, when reading the documentation of the zbar Python binding, it looks like a position field is available to get the location of the QR code:
import zbar
image = read_image_into_numpy_array(...) # whatever function you use to read an image file into a numpy array
scanner = zbar.Scanner()
results = scanner.scan(image)
for result in results:
print(result.type, result.data, result.quality, result.position)
The size of the QR code is probably also available as a field in result (e.g. result.size), and you can use it to find the 3 other corners.

Detect text in image and trace on them

I need some help with image processing , I'm working on a script which can detect Alphabets on the image and trace them , For example if there is a letter A in the Image then code has to detect it and trace(side-by-side not over same line) 3-4 times (with different colors) with given distance based on width of the text . As of now I'am able to detect the words and font and size using tesserocr module, but I'm unable to do the tracing thing .
import io
import tesserocr
from PIL import Image
with tesserocr.PyTessBaseAPI() as api:
image = Image.open("1d.png")
api.SetImage(image)
api.Recognize()
iterator = api.GetIterator()
print iterator.WordFontAttributes()
Thanks in advance #peace

Categories

Resources