Barcode decoding with pyzbar on raspberry pi - camera

I am using pyzbar to decode barcodes on Raspberry Pi 3 using Pi Camera v1 (resolution 1296x972). Qr codes are decoded very well. When decoding two dimensional barcodes (CODABAR), the success rate is very low.
I have tried saving one frame from the video stream and decode it with pyzbar on the Raspberry and it fails. When i try to decode the same image on Ubuntu, and decodes it successfully.
from pyzbar import pyzbar
from PIL import Image
img = Image.open('sampleImage.png')
d = pyzbar.decode(img)
print (d)
Any thoughts what may be the problem?
UPDATE:
The following image is my specific use case.
Because I am using Pi Camera v1 to take images, I tried to do adjustment to image sharpness:
from picamera import PiCamera
self.camera = PiCamera()
self.camera.sharpness = 100
The following image is with sharpness 100. However, pyzbar still fails to decode it on the Raspberry Pi.

You need to remove the black border from your image. According to this answer,
you can simply crop your image then feed the image to pyzbar.decode() function.
import cv2
from pyzbar import pyzbar
import numpy as np
def autocrop(image, threshold=0):
"""Crops any edges below or equal to threshold
Crops blank image to 1x1.
Returns cropped image.
"""
if len(image.shape) == 3:
flatImage = np.max(image, 2)
else:
flatImage = image
assert len(flatImage.shape) == 2
rows = np.where(np.max(flatImage, 0) > threshold)[0]
if rows.size:
cols = np.where(np.max(flatImage, 1) > threshold)[0]
image = image[cols[0]: cols[-1] + 1, rows[0]: rows[-1] + 1]
else:
image = image[:1, :1]
return image
if __name__ == "__main__":
image = cv2.imread('sampleImage.png')
crop = autocrop(image, 165)
d = pyzbar.decode(crop)
print(d)

Related

How to get intel realsense D435i camera serial numbers from frames for multiple cameras?

I have initialized one pipeline for two cameras and I am getting color and depth images from the same.
The problem is that I cannot find camera serial numbers for corresponding frames to determine which camera captured the frames.
Below is my code:
import pyrealsense2 as rs
import numpy as np
import cv2
import logging
import time
# Configure depth and color streams...
pipeline_1 = rs.pipeline()
config_1 = rs.config()
config_1.enable_device('938422072752')
config_1.enable_device('902512070386')
config_1.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
config_1.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
# Start streaming from both cameras
pipeline_1.start(config_1)
try:
while True:
# Camera 1
# Wait for a coherent pair of frames: depth and color
frames_1 = pipeline_1.wait_for_frames()
depth_frame_1 = frames_1.get_depth_frame()
color_frame_1 = frames_1.get_color_frame()
if not depth_frame_1 or not color_frame_1:
continue
# Convert images to numpy arrays
depth_image_1 = np.asanyarray(depth_frame_1.get_data())
color_image_1 = np.asanyarray(color_frame_1.get_data())
# Apply colormap on depth image (image must be converted to 8-bit per pixel first)
depth_colormap_1 = cv2.applyColorMap(cv2.convertScaleAbs(depth_image_1, alpha=0.5), cv2.COLORMAP_JET)
# Camera 2
# Wait for a coherent pair of frames: depth and color
frames_2 = pipeline_1.wait_for_frames()
depth_frame_2 = frames_2.get_depth_frame()
color_frame_2 = frames_2.get_color_frame()
if not depth_frame_2 or not color_frame_2:
continue
# Convert images to numpy arrays
depth_image_2 = np.asanyarray(depth_frame_2.get_data())
color_image_2 = np.asanyarray(color_frame_2.get_data())
# Apply colormap on depth image (image must be converted to 8-bit per pixel first)
depth_colormap_2 = cv2.applyColorMap(cv2.convertScaleAbs(depth_image_2, alpha=0.5), cv2.COLORMAP_JET)
# Stack all images horizontally
images = np.hstack((color_image_1, depth_colormap_1,color_image_2, depth_colormap_2))
# Show images from both cameras
cv2.namedWindow('RealSense', cv2.WINDOW_NORMAL)
cv2.imshow('RealSense', images)
cv2.waitKey(20)
finally:
pipeline_1.stop()
How can I find camera serial numbers after wait_for_frames() to determine which camera captured depth and color image.
I adopted your code, combined it with the C++ example posted by nayab to compose the following code that grabs the color image (only) of multiple RealSense cameras and stacks them horizontally:
import pyrealsense2 as rs
import numpy as np
import cv2
import logging
import time
realsense_ctx = rs.context() # The context encapsulates all of the devices and sensors, and provides some additional functionalities.
connected_devices = []
# get serial numbers of connected devices:
for i in range(len(realsense_ctx.devices)):
detected_camera = realsense_ctx.devices[i].get_info(
rs.camera_info.serial_number)
connected_devices.append(detected_camera)
pipelines = []
configs = []
for i in range(len(realsense_ctx.devices)):
pipelines.append(rs.pipeline()) # one pipeline for each device
configs.append(rs.config()) # one config for each device
configs[i].enable_device(connected_devices[i])
configs[i].enable_stream(rs.stream.color, 1920, 1080, rs.format.bgr8, 30)
pipelines[i].start(configs[i])
try:
while True:
images = []
for i in range(len(pipelines)):
print("waiting for frame at cam", i)
frames = pipelines[i].wait_for_frames()
color_frame = frames.get_color_frame()
images.append(np.asanyarray(color_frame.get_data()))
# Stack all images horizontally
image_composite = images[0]
for i in range(1, len(images)):
images_composite = np.hstack((image_composite, images[i]))
# Show images from both cameras
cv2.namedWindow('RealSense', cv2.WINDOW_NORMAL)
cv2.imshow('RealSense', images_composite)
cv2.waitKey(20)
finally:
for i in range(len(pipelines)):
pipelines[i].stop()
This will look for the connected devices and find the serial numbers.
They are saved in a list and you can use them to start the available cameras.
# Configure depth and color streams...
realsense_ctx = rs.context()
connected_devices = []
for i in range(len(realsense_ctx.devices)):
detected_camera = ealsense_ctx.devices[i].get_info(rs.camera_info.serial_number)
connected_devices.append(detected_camera)

how to save figure in vis_bbox without white background, when plotting with matplotlib?

i'm trying to save the image after vis_bbox prediction with its original image dimension.
my code:
from PIL import Image, ImageChops
import cv2
img = utils.read_image('/home/ubuntu/ui.jpg', color=True)
bboxes, labels,scores = model.predict([img])
bbox, label, score = bboxes[0], labels[0], scores[0],
colors = voc_colormap(label + 1)
bccd_labels = ('cell', 'cell')
vis_bbox(img, bbox, label_names=bccd_labels, instance_colors=colors, alpha=0.9, linewidth=1.0)
plt.axis("off")
plt.savefig("/home/ubuntu/ins.jpg")
while saving , it saves the image with white background and default size (432 *288).
i need to save the predicted image from vis_bbox with the original dimension (1300 *1300).
Any suggestions would be helpful!

Displaying an image in grayscale on matplot lib [duplicate]

I'm trying to use matplotlib to read in an RGB image and convert it to grayscale.
In matlab I use this:
img = rgb2gray(imread('image.png'));
In the matplotlib tutorial they don't cover it. They just read in the image
import matplotlib.image as mpimg
img = mpimg.imread('image.png')
and then they slice the array, but that's not the same thing as converting RGB to grayscale from what I understand.
lum_img = img[:,:,0]
I find it hard to believe that numpy or matplotlib doesn't have a built-in function to convert from rgb to gray. Isn't this a common operation in image processing?
I wrote a very simple function that works with the image imported using imread in 5 minutes. It's horribly inefficient, but that's why I was hoping for a professional implementation built-in.
Sebastian has improved my function, but I'm still hoping to find the built-in one.
matlab's (NTSC/PAL) implementation:
import numpy as np
def rgb2gray(rgb):
r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
return gray
How about doing it with Pillow:
from PIL import Image
img = Image.open('image.png').convert('L')
img.save('greyscale.png')
If an alpha (transparency) channel is present in the input image and should be preserved, use mode LA:
img = Image.open('image.png').convert('LA')
Using matplotlib and the formula
Y' = 0.2989 R + 0.5870 G + 0.1140 B
you could do:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def rgb2gray(rgb):
return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])
img = mpimg.imread('image.png')
gray = rgb2gray(img)
plt.imshow(gray, cmap=plt.get_cmap('gray'), vmin=0, vmax=1)
plt.show()
You can also use scikit-image, which provides some functions to convert an image in ndarray, like rgb2gray.
from skimage import color
from skimage import io
img = color.rgb2gray(io.imread('image.png'))
Notes: The weights used in this conversion are calibrated for contemporary CRT phosphors: Y = 0.2125 R + 0.7154 G + 0.0721 B
Alternatively, you can read image in grayscale by:
from skimage import io
img = io.imread('image.png', as_gray=True)
Three of the suggested methods were tested for speed with 1000 RGBA PNG images (224 x 256 pixels) running with Python 3.5 on Ubuntu 16.04 LTS (Xeon E5 2670 with SSD).
Average run times
pil : 1.037 seconds
scipy: 1.040 seconds
sk : 2.120 seconds
PIL and SciPy gave identical numpy arrays (ranging from 0 to 255). SkImage gives arrays from 0 to 1. In addition the colors are converted slightly different, see the example from the CUB-200 dataset.
SkImage:
PIL :
SciPy :
Original:
Diff :
Code
Performance
run_times = dict(sk=list(), pil=list(), scipy=list())
for t in range(100):
start_time = time.time()
for i in range(1000):
z = random.choice(filenames_png)
img = skimage.color.rgb2gray(skimage.io.imread(z))
run_times['sk'].append(time.time() - start_time)
start_time = time.time()
for i in range(1000):
z = random.choice(filenames_png)
img = np.array(Image.open(z).convert('L'))
run_times['pil'].append(time.time() - start_time)
start_time = time.time()
for i in range(1000):
z = random.choice(filenames_png)
img = scipy.ndimage.imread(z, mode='L')
run_times['scipy'].append(time.time() - start_time)
for k, v in run_times.items():
print('{:5}: {:0.3f} seconds'.format(k, sum(v) / len(v)))
Output
z = 'Cardinal_0007_3025810472.jpg'
img1 = skimage.color.rgb2gray(skimage.io.imread(z)) * 255
IPython.display.display(PIL.Image.fromarray(img1).convert('RGB'))
img2 = np.array(Image.open(z).convert('L'))
IPython.display.display(PIL.Image.fromarray(img2))
img3 = scipy.ndimage.imread(z, mode='L')
IPython.display.display(PIL.Image.fromarray(img3))
Comparison
img_diff = np.ndarray(shape=img1.shape, dtype='float32')
img_diff.fill(128)
img_diff += (img1 - img3)
img_diff -= img_diff.min()
img_diff *= (255/img_diff.max())
IPython.display.display(PIL.Image.fromarray(img_diff).convert('RGB'))
Imports
import skimage.color
import skimage.io
import random
import time
from PIL import Image
import numpy as np
import scipy.ndimage
import IPython.display
Versions
skimage.version
0.13.0
scipy.version
0.19.1
np.version
1.13.1
You can always read the image file as grayscale right from the beginning using imread from OpenCV:
img = cv2.imread('messi5.jpg', 0)
Furthermore, in case you want to read the image as RGB, do some processing and then convert to Gray Scale you could use cvtcolor from OpenCV:
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
The fastest and current way is to use Pillow, installed via pip install Pillow.
The code is then:
from PIL import Image
img = Image.open('input_file.jpg').convert('L')
img.save('output_file.jpg')
The tutorial is cheating because it is starting with a greyscale image encoded in RGB, so they are just slicing a single color channel and treating it as greyscale. The basic steps you need to do are to transform from the RGB colorspace to a colorspace that encodes with something approximating the luma/chroma model, such as YUV/YIQ or HSL/HSV, then slice off the luma-like channel and use that as your greyscale image. matplotlib does not appear to provide a mechanism to convert to YUV/YIQ, but it does let you convert to HSV.
Try using matplotlib.colors.rgb_to_hsv(img) then slicing the last value (V) from the array for your grayscale. It's not quite the same as a luma value, but it means you can do it all in matplotlib.
Background:
http://matplotlib.sourceforge.net/api/colors_api.html
http://en.wikipedia.org/wiki/HSL_and_HSV
Alternatively, you could use PIL or the builtin colorsys.rgb_to_yiq() to convert to a colorspace with a true luma value. You could also go all in and roll your own luma-only converter, though that's probably overkill.
Using this formula
Y' = 0.299 R + 0.587 G + 0.114 B
We can do
import imageio
import numpy as np
import matplotlib.pyplot as plt
pic = imageio.imread('(image)')
gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114])
gray = gray(pic)
plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))
However, the GIMP converting color to grayscale image software has three algorithms to do the task.
you could do:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def rgb_to_gray(img):
grayImage = np.zeros(img.shape)
R = np.array(img[:, :, 0])
G = np.array(img[:, :, 1])
B = np.array(img[:, :, 2])
R = (R *.299)
G = (G *.587)
B = (B *.114)
Avg = (R+G+B)
grayImage = img.copy()
for i in range(3):
grayImage[:,:,i] = Avg
return grayImage
image = mpimg.imread("your_image.png")
grayImage = rgb_to_gray(image)
plt.imshow(grayImage)
plt.show()
If you're using NumPy/SciPy already you may as well use:
scipy.ndimage.imread(file_name, mode='L')
Use img.Convert(), supports “L”, “RGB” and “CMYK.” mode
import numpy as np
from PIL import Image
img = Image.open("IMG/center_2018_02_03_00_34_32_784.jpg")
img.convert('L')
print np.array(img)
Output:
[[135 123 134 ..., 30 3 14]
[137 130 137 ..., 9 20 13]
[170 177 183 ..., 14 10 250]
...,
[112 99 91 ..., 90 88 80]
[ 95 103 111 ..., 102 85 103]
[112 96 86 ..., 182 148 114]]
With OpenCV its simple:
import cv2
im = cv2.imread("flower.jpg")
# To Grayscale
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imwrite("grayscale.jpg", im)
# To Black & White
im = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite("black-white.jpg", im)
I came to this question via Google, searching for a way to convert an already loaded image to grayscale.
Here is a way to do it with SciPy:
import scipy.misc
import scipy.ndimage
# Load an example image
# Use scipy.ndimage.imread(file_name, mode='L') if you have your own
img = scipy.misc.face()
# Convert the image
R = img[:, :, 0]
G = img[:, :, 1]
B = img[:, :, 2]
img_gray = R * 299. / 1000 + G * 587. / 1000 + B * 114. / 1000
# Show the image
scipy.misc.imshow(img_gray)
When the values in a pixel across all 3 color channels (RGB) are same then that pixel will always be in grayscale format.
One of a simple & intuitive method to convert a RGB image to Grayscale is by taking the mean of all color channels in each pixel and assigning the value back to that pixel.
import numpy as np
from PIL import Image
img=np.array(Image.open('sample.jpg')) #Input - Color image
gray_img=img.copy()
for clr in range(img.shape[2]):
gray_img[:,:,clr]=img.mean(axis=2) #Take mean of all 3 color channels of each pixel and assign it back to that pixel(in copied image)
#plt.imshow(gray_img) #Result - Grayscale image
Input Image:
Output Image:
image=myCamera.getImage().crop(xx,xx,xx,xx).scale(xx,xx).greyscale()
You can use greyscale() directly for the transformation.

How to save an animated GIF to a variable using Pillow

I found out from here that I can create and save animated GIFs using Pillow. However, it doesn't look like the save method returns any value.
I can save the GIF to a file and then open that file using Image.open, but that seems unnecessary, given that I don't really want the GIF to be saved.
How can I save the GIF to a variable, rather than a file?
That is, I would like to be able to do some_variable.show() and display a GIF, without ever having to save the GIF onto my computer.
To avoid writing any files, you can just save your image to BytesIO object. For example:
#!/usr/bin/env python
from __future__ import division
from PIL import Image
from PIL import ImageDraw
from io import BytesIO
N = 25 # number of frames
# Create individual frames
frames = []
for n in range(N):
frame = Image.new("RGB", (200, 150), (25, 25, 255*(N-n)//N))
draw = ImageDraw.Draw(frame)
x, y = frame.size[0]*n/N, frame.size[1]*n/N
draw.ellipse((x, y, x+40, y+40), 'yellow')
# Saving/opening is needed for better compression and quality
fobj = BytesIO()
frame.save(fobj, 'GIF')
frame = Image.open(fobj)
frames.append(frame)
# Save the frames as animated GIF to BytesIO
animated_gif = BytesIO()
frames[0].save(animated_gif,
format='GIF',
save_all=True,
append_images=frames[1:], # Pillow >= 3.4.0
delay=0.1,
loop=0)
animated_gif.seek(0,2)
print ('GIF image size = ', animated_gif.tell())
# Optional: display image
#animated_gif.seek(0)
#ani = Image.open(animated_gif)
#ani.show()
# Optional: write contents to file
animated_gif.seek(0)
open('animated.gif', 'wb').write(animated_gif.read())
In the end, variable animated_gif contains contents of the following image:
However, displaying an animated GIF in Python is not very reliable. ani.show() from the code above displays only first frame on my machine.

A real time Spectrum analyser with pyaudio in python on Raspi

I am trying to get an fft plot on realtime audio using a USB microphone plugged into my raspi. I want to be able to activate an LED when a certain frequency is detected through the fft plot. I have so far tried to get just a live sound wave to be plotted but I am having trouble. I have followed this video: https://www.youtube.com/watch?v=AShHJdSIxkY&lc=z22efhti3uaff52pv04t1aokgg3rlotuia3kw5mpcsnubk0h00410.1510779722591217
I have tried changing the chunk size to a greater value and a lower value but have had no success.For some reason I get the -9981 error but it takes a long time to print the error. No plot is displayed. I have even tried overclocking my Raspberry Pi to see if that would work but it still doesn't work.
I was wondering if anyone else had tried something like this on their Pi and if it was possible or if I had to do it using a different package other than pyaudio.
Here is my python code:
import pyaudio
import struct
import numpy as np
import matplotlib.pyplot as plt
CHUNK = 100000
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
p = pyaudio.PyAudio()
stream = p.open(
format = FORMAT,
channels = CHANNELS,
rate = RATE,
input = True,
output = True,
frames_per_buffer = CHUNK,
start = True
)
fig, ax = plt.subplots()
x = np.arange(0, 2 * CHUNK, 2)
line, = ax.plot(x, np.random.rand(CHUNK))
ax.set_ylim(0, 255)
ax.set_xlim(0, CHUNK)
while True:
data = stream.read(CHUNK)
data_int = np.array(struct.unpack(str(CHUNK*2) + 'B', data), dtype='b')[::2] + 127
line.set_ydata(data_int)
fig.canvas.draw()
fig.canvas.flush_events()
To display add:
plt.show(block=False)
after
ax.set_xlim(0, CHUNK)
But with rpi you have to configure your usb sound card as default card