0

I have a RAW image that is saved as .dng from a phone's camera. I want to segment the colors with the OpenCV library in Python. The picture is primarily black and green and I want to get the values of the green parts of the image. I've not worked with images in this way and am completely clueless. The tutorial I am following says to convert the image to H.S.V. color space and to use a mask, but I'm running into problems with the mask, if not in other steps. I'm using Google Colabs.

import cv2
import matplotlib.pyplot as plt
import numpy as np
import os
from google.colab import drive
import imageio
import scipy.misc
import skimage.filters
import skimage.metrics
from PIL import Image

# Colabs...
!pip install rawpy

import rawpy

# Colabs...
!pip install ExifRead

import exifread

#image
plate = rawpy.imread('/content/drive/MyDrive/Colab Notebooks/Copy of 0724201706a.dng')

#EXIF
plate_x = open('/content/drive/MyDrive/Colab Notebooks/Copy of 0724201706a.dng', 'rb')

#There are several lines returned. I've left this out for now...
plate_tags = exifread.process_file(plate_x)
plate_tags

plt.imshow(plate.raw_image)

picture of raw image as imported

plate_rgb = plate.postprocess( use_camera_wb=True)

plt.imshow(plate_rgb)

RBG version of image

plate_rgb.shape
(5312, 2988, 3)

These are a slightly edited RGB, the green channel, and blue channel of the RGB image.

enter image description here

Histograms of the values for each channel in R.G.B. image. The other channels are 0, but green has various values.

enter image description here

I supplied all this info to try to describe the RAW image and the R.G.B.

The tutorial says to convert to the H.S.V. color space. I saw somewhere that the image comes in as B.G.R., so I tried two approaches:

plateRGB_hsv = cv2.cvtColor(plate_rgb, cv2.COLOR_RGB2HSV)
plateBGR_hsv = cv2.cvtColor(plate_rgb, cv2.COLOR_BGR2HSV)

two versions of HSV

# A lower and upper threshold for mask
hsv_green_lo = (59, 100, 135) #h = 50, s = 100, v = 135)
hsv_green_hi = (75, 250, 255) #h = 75, s = 250, v = 255)

plateRGB_hsv.shape
(5312, 2988, 3)

# Create mask
green_thr = cv2.inRange(plateRGB_hsv, hsv_green_lo, hsv_green_hi)

# Apply mask
img_msk = cv2.bitwise_and(plateRGB_hsv, plateRGB_hsv, green_thr)

plt.subplot(1,2,1)
plt.imshow(green_thr)
plt.subplot(1,2,2)
plt.imshow(img_msk)
plt.show()

Output of the inRange (mask layer creation) and bitwise_and (mask application). enter image description here

rgb_out = cv2.bitwise_and(plate_rgb, plate_rgb, green_thr)

plt.imshow(rgb_out)
plt.plot()

Apply mask and this is output.

rgb after mask

So I didn't seem to create the mask properly? And with the bad mask, there was no change when bitwise_and ran it looks like? I don't know why the mask failed. Is the fact that the R.G.B. or H.S.V. is in three channels complicating the mask and mask application?

The image is here.

EDIT after comments and submitted answer:

I was not clear about what I want my output to look like. I said "green", but really I want it to look like this:

enter image description here

I made a new array with just the green channel as advised. green_c = plate_rgb[...,1]

But now, I'm confused about how to create a mask. Since the array is just one level, I think of it as a "layer", like in G.I.S. or GIMP, how do I change the unwanted values to black? Sorry if this is obvious. I'm still pretty new to Python.

John Polo
  • 547
  • 1
  • 8
  • 25
  • Can you share the DNG image, please? You may need to use Dropbox or Google Drive or somesuch. – Mark Setchell Jan 04 '21 at 23:16
  • @MarkSetchell I added a link to a Google Drive. – John Polo Jan 04 '21 at 23:27
  • check this(worked for me) [https://stackoverflow.com/a/33639608/13002578](https://stackoverflow.com/a/33639608/13002578) – lnx Jan 04 '21 at 23:46
  • if you want to select one of the base colors red, green or blue, there's no need to convert the RGB image to HSV. This only comes in handy when the color to select is stretched over a wide RGB range which might be much smaller in another color space such as HSV. – Stef Jan 05 '21 at 12:46

1 Answers1

1

I am not really sure what you think the problem is. Basically, the Red and Blue channels of your image are empty (look at their mean values in the output below) and you may as well discard them and just use the Green channel as your mask.

#!/usr/bin/env python3

import rawpy
import matplotlib.pyplot as plt
import numpy as np

# Load and process raw DNG
plate = rawpy.imread('raw.dng')
rgb = plate.postprocess()

# Show what we've got
print(f'Dimensions: {rgb.shape}, dtype: {rgb.dtype}')
R = rgb[...,0]
print(f'R channel: min={R.min()}, mean={R.mean()}, max={R.max()}')
G = rgb[...,1]
print(f'G channel: min={G.min()}, mean={G.mean()}, max={G.max()}')
B = rgb[...,2]
print(f'B channel: min={B.min()}, mean={B.mean()}, max={B.max()}')

# Display green channel
plt.imshow(G, cmap='gray')
plt.show()

enter image description here

Output for your image

Dimensions: (5312, 2988, 3), dtype: uint8
R channel: min=0, mean=0.013673103558813567, max=255
G channel: min=0, mean=69.00267554908389, max=255
B channel: min=0, mean=0.017269189710649828, max=255

Keywords: Python, image processing, rawpy, DNG, Adobe DNG format.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432