I have small r g b image. Imake it gray.
original = cv2.imread('im/auto5.png')
print(original.shape) # 27,30,3
print(original[13,29]) # [254 254 254]
orig_gray = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
print(orig_gray.shape) # 27,30
Is it in this array info about white and black pixels? Or it lost this data? What mean this numbers?
print(orig_gray[5,5]) #6
At r g b image it mean color (3 digits, like [254,254,254]). But what mean one digit in my case with gray image? I want to get quanity of white pixels for my recognising.
Once you convert to gray scale there is only one value for each 'pixel' or index in the 2D array which represents the brightness in the original RGB image. The RGB image is essentially 3 of these arrays which represent the brightness for each of the three colors.
The idea of a 'white pixel' is a little confusing. I guess you could say any location in the grayscale array with a value of 255 is a white pixel. That would be an RGB pixel which is fully saturated at (255, 255, 255). There is basically only one value for each pixel after converting to gray scale.
Hope that helps.
Related
I currently have a code for measuring the average brightness of an RGB image.
When i run this with a black and white image, the RGB values are the same, e.g. 37, 37, 37
I have no idea about colours etc but i dont think this is correct
Here is my code at the moment:
from PIL import Image
from math import sqrt
imag = Image.open("../Images/pexels-photo-57905.jpeg")
imag = imag.convert ('RGB')
imag.show()
X,Y = 0,0
pixelRGB = imag.getpixel((X,Y))
R,G,B = pixelRGB
brightness = sum([R,G,B])/3 ##0 is dark (black) and 255 is bright (white)
print(brightness)
print(R,G,B)
In a nutshell, i must convert an RGB image into grayscale, which im using .convert('LA') for, i must THEN measure the brightness of the image by adding the black and white values then dividing them by 2
Are these codes correct to measure the average brightness of a greyscale image? What do the three lines below mean? Does it return the average brightness of the whole picture, or just (0,0)?
X,Y = 0,0
pixelRGB = imag.getpixel((X,Y))
R,G,B = pixelRGB
I want to convert any image to grayscale, but I don't understand the difference between these implementations.
image = cv2.imread('lenna.jpg')
gray = cv2.cvtColor(image, cv2.IMREAD_GRAYSCALE)
gray1 = rgb2gray(image)
gray2 = cv2.imread('lenna.jpg', cv2.IMREAD_GRAYSCALE)
image1 = Image.open('lenna.jpg', 'r')
gray3 = image1.convert('L')
When I plot them, I get them in blue scale, green scale, green scale and gray respectively. When I should use each one?
You've encountered a spot where Python's type system isn't protecting you in the way that C++ would.
cv2.IMREAD_GRAYSCALE and cv2.COLOR_BGR2GRAY are values from different enumerations. The former, whose numerical value is 0, applies to cv2.imread(). The latter, whose numerical value is 6, applies to cv2.cvtColor(). C++ would have told you that cv2.IMREAD_GRAYSCALE can't be passed to cv2.cvtColor(). Python quietly accepts the corresponding int value.
Thus, you think you're asking cv2 to convert a color image to gray, but by passing cv2.IMREAD_GRAYSCALE, cv2.cvtColor() sees the value 0, and thinks you're passing cv2.COLOR_BGR2BGRA. Instead of a grayscale image, you get the original image with an alpha channel added.
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
is what you need instead.
The other issue you're seeing, assuming you're using a Jupyter notebook, is that cv2 layers color planes in BGR order instead of RGB. To display them properly, first do
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
and then display the result.
The images that are not gray are the still 3d arrays, that is to say they still somehow retain color information, the reason you are seeing blue and green is because in those 3d arrays the red and green channels in the first case and the blue & red channels in the second have been reduced to 0 leaving only the blue and green that you see.
In order to read the image as grayscale you would use
img_gray=cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
This will yield a 2d array with values between 0 and 255 corresponding to how bright the pixel should be instead of how bright each of the 3 color channels of the pixel should be.
In OpenCV python, say we read an image with cv2.imread and get a BGR numpy array. We next generate a mask with the cv2.inRange command. The mask has the same width/height and each mask pixel is either black or white.
I want to copy a region from the mask (taken as an image of black and white pixels) onto a region of the color image.
How do I do that? This does not work
img[10:20,10:20] = mask[10:20,10:20]
Must I convert the mask to BGR image first? If so how?
Edit: I do not want to apply the whole mask to the image as in apply mask to color image. Another way to say what I want: see the mask as a black and white image. I want to copy a region of that image (as a set of black or white pixels) onto another image. The resulting image will be a color image except for one smaller rectangular region that contains only black or white pixels. The result will be similar to if I in photoshop copy a rectangular area of a black/white image and past that rectangle onto an area of a color image.
(I'm new to OpenCV)
If you try to do it with a single channel (grayscale) mask directly, the shapes of the array slices will not be the same, and the operation will fail.
>>> img[10:20,10:20] = mask[10:20,10:20]
ValueError: could not broadcast input array from shape (10,10) into shape (10,10,3)
You have to convert the mask to BGR, which will make it 3 channels, like the original image.
>>> bgr_mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
>>> img[10:20,10:20] = bgr_mask[10:20,10:20]
Let say I have this rose (Do not care about the background, only the white leaves are important).
I transform it to a grayscale picture:
grayscaled=cv2.imread('white_rose.png',cv2.IMREAD_GRAYSCALE)
How can I change every white pixel to a red one under the condition the red color (R=255) will have the same contrast as the white one has ? Meaning I want to see the white leaves in red color but with the same L value of every pixel that in grayscaled ?
You need to loop over your grey image and create a new coloured image by yourself.
For each pixel, you can replace the R value of your coloured image with the remainder of dividing of 255 and relative grey value:
import cv2
import numpy as np
img = cv2.imread('5585T.jpg')
print type(img)
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
new=[[[0,0,255%j] for j in i] for i in img_gray]
dt = np.dtype('f8')
new=np.array(new,dtype=dt)
cv2.imwrite('img.jpg',new)
and with new=[[[255%j,255%j,j] for j in i] for i in img_gray] :
I learned this method from a SPIE Proceeding article, they used the twice HSV transformation for shadow detection. In their paper, the method was stated as following:
Firstly, the color model of the image is transformed from RGB to HSV,
and the three components of the HSV model are normalized to 0 to 255,
then the image is transformed from RGB to HSV once again. Thirdly, the
image is turned into a gray image from a color image, only the gray
value of the red component is used. Fourthly, the OTSU thresholding
method is used to produce a threshold by which the image is converted
to a binary image. Since the gray value of the shadow area is usually
smaller than those areas which are not covered by shadow, the
objective is pixels whose gray value is below the threshold, and
background is pixels whose gray value is beyond the threshold.
Do the second and third steps make sense?
The second and third statements absolutely don't make any sense whatsoever. Even the pipeline is rather suspicious. However, after re-reading that statement probably a dozen times, here is what I came up with. Apologies for any errors in understanding.
Let's start with the second point:
Firstly, the color model of the image is transformed from RGB to HSV, and the three components of the HSV model are normalized to 0 to 255, then the image is transformed from RGB to HSV once again
You're well aware that transforming an image from RGB to HSV results in another three channel output. Depending on which platform you're using, you'll either get 0-360 or 0-1 for the first channel or Hue, 0-100 or 0-255 for the second channel or Saturation, and 0-100 or 0-255 for the third channel or Value. Each channel may be unequal in magnitude when comparing with the other channels, and so these channels are normalized to the 0-255 range independently. Specifically, this means that the Hue, Saturation and Value components all get normalized so that they all span from 0-255.
Once we do this, we now have a HSV image where each channel ranges from 0-255. My guess is they call this new image a RGB image because the channels all span from 0-255, just like any 8-bit RGB image would. This also makes sense because when you're transforming an image from RGB to HSV, the dynamic range of the channels all span from 0-255, so my guess is that they normalize all of the channels in the first HSV result to make it suitable for the next step.
Once they normalize the channels after doing HSV conversion as per above, they do another HSV conversion on this new result. The reasons why they would do this a second time are beyond me and don't make any sense, but that's what I gathered from the above description, and that's what they probably mean by "twice HSV transformation" - To transform the original RGB image to HSV once, normalize that result so all channels span from 0-255, then re-apply the HSV conversion again to this intermediate result.
Let's go to the third point:
Thirdly, the image is turned into a gray image from a color image, only the gray value of the red component is used.
The output after you transform the HSV image a second time, the final result is simply taking the first channel which is inherently a grayscale image and is the "red" channel. Coincidentally, this also corresponds to the Hue after you do a HSV conversion. I'm not quite sure what properties the Hue channel holds after converting the image using HSV twice, but maybe it worked for this particular method.
I decided to give this a whirl and see if this really works. Here's an example image of a shadow I found online:
Source: http://petapixel.com/
The basic pipeline is to take an image, convert it into HSV, renormalize the image so that the values are 0-255 again, do another HSV conversion, then do an adaptive threshold via Otsu. We threshold below the optimal value to segment out the shadows.
I'm going to use OpenCV Python, as I don't have the C++ libraries set up on my computer here. In OpenCV, when converting an image to HSV, if the image is unsigned 8-bit RGB, the Saturation and Value components are automatically scaled to [0-255], but the Hue component is scaled to [0-179] in order to fit the Hue (which is originally [0-360)) into the data type. As such, I scaled each value by (255/179) so that the Hue gets normalized to [0-255]. Here's the code I wrote:
import numpy as np # Import relevant libraries
import cv2
# Read in image
img = cv2.imread('shadow.jpg')
# Convert to HSV
hsv1 = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Renormalize Hue channel to 0-255
hsv1[:,:,0] = ((255.0/179.0)*hsv1[:,:,0]).astype('uint8')
# Convert to HSV again
# Remember, channels are now RGB
hsv2 = cv2.cvtColor(hsv1, cv2.COLOR_RGB2HSV)
# Extract out the "red" channel
red = hsv2[:,:,0]
# Perform Otsu thresholding and INVERT the image
# Anything smaller than threshold is white, anything greater is black
_,out = cv2.threshold(red, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Show the image - shadow mask
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
This is the output I get:
Hmm.... well there are obviously some noisy pixels, but I guess it does work.... kinda!