Thresholding for a single RGB channel and how to put the image back together

Hey,

I need to split the image to separate RGB channels, then apply a different set of thresholds on each of it, and finally put the image back together.

I’ve learned that to extract a channel I should pass rgb_channel=X, but for thresholding, RGB images with img.binary[] take LAB colorspace as arguments. Do I need to manually calculate LAB values of RGB thresholds for each value or is there implemented solution? To be specific, I need to cut off only the 190-255, 160-255 and 127-255 parts of the RGB image.

Also: how to put the image back together after thresholding on single channels?

Thanks for your help :slight_smile:

Hi, you want to allocate 3 extra image buffer. Use the to_grayscale() with copy_to_fb targeting one of each buffer and then a different rgb channel extraction per.

This will give you three grayscale images. You can then threshold these by doing binary(). Then b_or() the images together.

Wait, you said not binary. Anyway, when you get the three grayscale images you can threshold them. I believe we have a method that just zeros values outside of a threshold.

Not sure how to recombine. I guess you can draw_image() them all on the same output buffer using a color table to re color the grayscale back to rgb.

Thanks! I will try this out!

Ok, I have written the code that produces what I need. However, I am wondering: I store the original image in the frame buffer, and the produced rgb mask on the heap. It works for low res, but I think there would be a problem with higher resolutions - mask could possibly not fit onto the heap.

Is there a smarter way to do this?

r_th=(190, 255)
g_th=(160,255)
b_th=(190,255)

import sensor, image, time

sensor.reset()                      
sensor.set_pixformat(sensor.RGB565) 
sensor.set_framesize(sensor.QVGA)  
sensor.skip_frames(time = 2000)     
i=1

while(i==1):
    img = sensor.snapshot(copy_to_fb=True)         
    img.save('src.bmp')

    img=image.Image('src.bmp', copy_to_fb=True, pause=True)
    img_buf_r=img.copy(rgb_channel=0, copy_to_fb=True)
    img_buf_r.save('buf_r.bmp')
    img_buf_r.to_grayscale(copy_to_fb=True)
    img_buf_r.binary([r_th], invert = 1)
    img_buf_r.save('r_mask.bmp')




    img=image.Image('src.bmp', copy_to_fb=True, pause=True)
    img_buf_g=img.copy(rgb_channel=1, copy_to_fb=True)
    img_buf_g.save('buf_g.bmp')
    img_buf_g.to_grayscale(copy_to_fb=True)
    img_buf_g.binary([g_th], invert=1)
    img_buf_g.save('g_mask.bmp')




    img=image.Image('src.bmp', copy_to_fb=True, pause=True)
    img_buf_b=img.copy(rgb_channel=2, copy_to_fb=True)
    img_buf_b.save('buf_b.bmp')
    img_buf_b.to_grayscale(copy_to_fb=True)
    img_buf_b.binary([b_th], invert=1)
    img_buf_b.save('b_mask.bmp')




    mask_rgb=img_buf_r.b_and(img_buf_g)
    mask_rgb=mask_rgb.b_and(img_buf_b)
    mask_rgb.save("mask.bmp") 


    img=image.Image('src.bmp', mask=mask_rgb, copy_to_fb=True, pause=True)
    mask_rgb=image.Image('mask.bmp')
    mask_rgb.invert()
    img=image.Image('src.bmp', mask=mask_rgb, copy_to_fb=True)
    img.clear(mask=mask_rgb)
    img.save('output.bmp')

    time.sleep_ms(1000)
    i=0         

I’ve actually helped myself.

The answer is alloc_extra_fb. By using

mask_rgb=sensor.alloc_extra_fb(sensor.width(), sensor.height(), sensor.RGB565)`

and replacing it with command

mask_rgb.replace(img_buf_r)

I am able to run the b_and later on, without using the heap. Problem solved!