Capturing monochromatic images

OpenCV, Python and other image processing questions
Post Reply
fraserbarton
Posts: 18
Joined: Sun Oct 06, 2019 11:55 am

Capturing monochromatic images

Post by fraserbarton »

I am looking to capture monochromatic images for my project and am wondering of the best way to achieve this.

At the moment I am capturing RGB output from the camera into a numpy array and then getting a grayscale image by performing a dot-product of the RGB matrix with an RGB to grayscale conversion. Something like:

Code: Select all

def rgb2grey(rgb):
	return np.dot(rgb[...,:3], [0.1140, 0.5870, 0.2989]).astype(int)
However I am now thinking that a more efficient way to do this would be to grab the Y channel (luma) component of a YUV output.

I want my output to be a 2D matrix so that I work it forward more easily. E.g. for a 1280 x 480 image I would like a 1280 x 480 matrix where each element is between 0 and 255.

I have tried to achieve this in two separate ways.

First outputting the Y data from the YUV data into an array of the same resolution:

Code: Select all

import time
import picamera
import picamera.array
import numpy as np

with picamera.PiCamera() as camera:
    camera.resolution = (100, 100)
    time.sleep(2)
    y_data = np.empty((112, 128), dtype=np.uint8)
    try:
        camera.capture(y_data, 'yuv')
    except IOError:
        pass
    y_data = y_data[:100, :100]
    # y_data now contains the Y-plane only
    
Unfortunately the image produced from this is not as I would expect, clearly something has gone very wrong. Image attached.

Secondly I tried to use the PiYUVArray method.

Code: Select all

import time
import picamera
import picamera.array

with picamera.PiCamera() as camera:
    with picamera.array.PiYUVArray(camera) as stream:
        camera.resolution = (1280, 720)
        camera.start_preview()
        time.sleep(2)
        camera.capture(stream, 'yuv')
        print(stream.array.shape)
       
The trouble with this is that the shape of the array outputted is (720, 1280, 3). How can I reduce this to a (720, 1280) matrix for just the Y component?
Attachments
YUV_output.png
YUV_output.png (113.04 KiB) Viewed 4287 times
correct_image.jpeg
correct_image.jpeg (2.55 MiB) Viewed 4287 times

User avatar
Realizator
Site Admin
Posts: 900
Joined: Tue Apr 16, 2019 9:23 am
Contact:

Re: Capturing monochromatic images

Post by Realizator »

Hi Fraserbarton,

1. To start with, in our C++ example we used a trick available in raspividyuv utility. It is a "--luma" key, which force system to give you just a luma component. Unfortunately, this option is not available at PiCamera. But you can use a transmission over pipe, like in this Gist. Our experience shows that it works with Python, but unstable (can crash once per 3-5 runs). WIth C++ this approach is stable.

2. Actually, your YUV output is not broken, but just have a horizontal "shift" for each row. You set 100x100 resolution, but actually low-level capture part has some resolution requirements (like width is dividable by 32 and height by 16). When you use an "easy" capture, PiCamera will actually scale image to your resolution, if it not fits internal rules. But with the YUV you need to keep follow these requirements, as it is low-level access.

Luckily Dave Jones (PiCamera author) put this useful answer on StackOverflow. And the first piece of Python code does right this thing that you need - it takes Y component of the captured image only. Please notice camera resolution (120x90) and array size (96, 128) he used for the frames:
https://raspberrypi.stackexchange.com/q ... wnsampling
Eugene a.k.a. Realizator

Post Reply