what does the column imply when randomly generating an image using np.random.randint
img = np.random.randint(255, size=(4,4,3), dtype='uint8')
This creates a 4 by 4 pixel, with a matrix of 3 columns.
img = np.random.randint(255, size=(4,4,4), dtype='uint8')
This creates a 4 by 4 pixel, with a matrix of 4 columns.
What is the job of the column in the matrix in this case?
Nice question. We usually call channels what you call columns.
A RGB image has 3 channels: red, green and blue.
A CMYK image has four channels: cyan, magenta, yellow, and black.
Visually:
One can not say what the components of a pixel represent. Or at least not with certainty. It depends on the color space [wiki] you select.
In order to store a color, you need to represent that color. There are several ways to do that. A common way to do that is with the RGB color model [wiki]. Where one uses three channels: one for Red, one for Green and one for Blue. This model is based on the assumption that the human eye has three kinds of light receptors, for each of these colors. It is common in for monitors as well, since a computer monitor has three sorts of subpixels each to render one of the color channels. Sometimes an extra channel Alpha is added, making it an ARGB color scheme. The alpha channel then describes the level of transparency of that pixel. This is useful if you for example want to add one image over another one, and some parts of the image.
Another color system is the HSL color system, where the color space is seen as a cylindrical shape one, and the three attribute Hue, Saturation, and Lightness describe the angle, radius and height in the cylinder respectively. This is contrast to an RGB color system, that can be seen as a cube.
For printing purposes, often the CMYK color model is used: with a channel for Cyan, Magent, Yellow and Black. These are often the ink cardridges in a basic printer.
In short, you thus can not tell what the color scheme is. According to numpy, this is just a 4×4×3 or 4×4×4 array. It is only by interpreting the numbers, for example according to a color scheme, that we can make sense out of it.
OpenCV has a function to convert one color scheme into another. As you can see, it supports a large range of conversions. It has extensive documentation on the color schemes as well.
Related
I'm trying to determine the color hierarchy of some lines in an image, using the images library in python.
If you are not familiar with the images library, it represents an image as a list of lists (a matrix). Each item inside the inner list is a tuple with RGB values (e.g. (255, 255, 255)).
How would this be possible? The background color is known, the lines are always straight and in different colors.
A sample image can be seen here: https://imgur.com/J35IT9k
The answer for this image would be: white first, red second, green third and then the background color (gray) last.
The colors would be represented in tuples of RGB values of course
As you have been unable to provide any information or references to this mystery "images" library, I am suggesting a different approach.
If your images are always in a plus shape, i.e. axis-aligned and symmetrical, you can probably use a simple heuristic to find the layer ordering.
the image is symmetrical, so you only need to process the rows or the columns but not both
the grey pixels are a distraction, make them black (i.e. zero) so they contribute nothing
sum across the rows with np.sum(..., axis=1) so you find the horizontal lines, i.e. where the row sums to a large number
look at each line you find, and test the number of unique colours in it - if it is 1 (i.e. white in your diagram) it is top-most. If it is 2, it is the next layer down and so on.
Regarding the following cv2.inRange(...) invocation:
mask = cv2.inRange(quantized_img, color, color)
Must the 'quantized_img' and 'color' arguments be strictly in HSV or it's OK to have RGB image and RGB 'color'? It seems that RGB works for me, but all examples I could find are HSV-based. So I'm concerned about the correct usage.
Thanks!
In general, use whatever color space you like. RGB/BGR is fine, HSV is fine, something completely made up (with cv.transform) is fine too.
inRange spans a "cube".
Think about it. Imagine a 3D plot with R,G,B axes, or with H,S,V axes. In RGB space, the faces of the cube are aligned with those RGB axes. in HSV space the faces of the cube are aligned with those axes instead.
Now, a cube spanned in RGB space, when transformed into HSV space, is not aligned with the axes in HSV space. In fact it's not even a cube anymore, but likely some kind of torus or section of a cone or something. Same goes the other way around.
If the area of values you're interested in, in whatever space you choose, is flat or even stick-shaped (instead of a mostly spherical cloud), the cube you have to span might align very badly with the area of values you are interested in, and would have to include a lot of values you aren't interested in.
So you move into another color space where your values of interest are somewhat better aligned with the axes in that space. Then the cube spanned by inRange fits your purpose better.
Imagine a "stick" in RGB space going from the black corner to the white corner. It represents "colors" with no saturation to them (because colors are in the other six corners of the cube). Try spanning a cube over that area. Doesn't fit well.
In HSV space however, it's trivial. Usually it's visualized as a cylinder/inverted cone though... span a thin cylinder in the center: any Hue (angle), any Value (height), with very low Saturation (close to the center axis). If you took HSV as a cube, you'd span a thin wall instead. And it all would fit very well.
The explanation given by #Christoph Rackwitz is completely correct. I'll just like to add a few tips observed by me.
HSV and Lab color spaces are the best ones for color segmentation.
Keep BGR color space as probably the last option.
Do not just blindly start finding the range in HSV or Lab color segmentation for your color. Look for other methods too.
Other methods include:
Visualize each color channel of HSV and Lab separately as a grayscale image. You might see some pattern there only.
One thing that helped in my case was I did Otsu's thresholding on "Hue" and "Saturation" channels of my image and then performed a bitwise OR operation on their output. The final image had everything I need without any errors. Do a hit-and-try on your input images to observe such patterns. This helps a lot.
Short form: is there any color space similar to CIELab but with the middle position on the two color axes occupied by browns rather than greys, as sketched below? Ideally with a Python interface to convert to and from RGB.
Values on a third, 'lightness' dimension would take each of these possible colors from black to white.
link to image (sorry, not enough rep here to put it inline)
Context: For a simulation, every entity can vary on two variables. When visualizing the entities I'd like to use color to give a fairly intuitive idea of the two values for each entity. RGB does not seem a convenient color space for this, as changes in values do not very intuitively correspond to changes in color. CIELab (see above link) is much closer to what I need, as it has two color dimensions (red-to-green, yellow-to-blue) plus a Lightness dimension; and there already exists a python module to do the math. The one hitch for me: a value of zero on both color dimensions results in a shade of grey (black at Lightness=0 and white at L=100). Instead I would like lightness level (with black and white as extremes) to only come in if the visualisation involves shading; with a flat, unshaded visualization there should be no black, white or grey. For the middle position on the two color axes, brown seems somehow intuitive to me - perhaps because mixing multiple paint colors often seems to give brown.
Maybe such a consistent color space is difficult/impossible to construct as the brown in the middle might conflict with e.g. dark shades of orange. As a 'color novice' I'd just welcome some input whether something like this exists or is at all possible.
I suppose I could associate variable values and RGB color values by hand. But that seems cumbersome and inelegant if there exists a more consistent way.
I'm looking just for an idea/conception to resolve my problem.
I need to CHECK if the color of a surface does not exceed a certain gray level. So I thought to calculate its luminance.
Problem is that colors like this one #BCB0F5 will give me an acceptable gray level, however the color of the surface must not look that blue for the human eyes. It must look (for human eyes) just as a certain gray level (black and white).
How can I resolve this problem ?
Thank you for any hints.
In a perceptual model of colour, we can talk of a particular colour's luminance and chromaticity (it's "brightness" and it's "quality"). By converting the samples you have from RGB to CIELAB (via ColorPy say), you can filter out colours which are brighter than your desired grey (L_sample > L_grey) and whose distance from the white point are greater than a JND (e.g. sqrt(a_sample**2 + b_sample**2) > 2.3)
This image is just an example. Top right is the original image, top left is the hue, bottom left the saturation and bottom right is the value. As can be easily seen both H and S are filled with artifacts. I want to reduce the brightness so the result picks a lot of this artifacts.
What I am doing wrong?
My code is simply:
vc = cv2.VideoCapture( 0 )
# while true and checking ret
ret, frame = vc.read()
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
cv2.imshow("h", frame_hsv[:,:,0])
cv2.imshow("s", frame_hsv[:,:,1])
cv2.imshow("v", frame_hsv[:,:,2])
I feel there is a misunderstanding in your question. While the answer of Boyko Peranov is certainly true, there are no problems with the images you provided. The logic behind it is the following: your camera takes pictures in the RGB color space, which is by definition a cube. When you convert it to the HSV color space, all the pixels are mapped to the following cone:
The Hue (first channel of HSV) is the angle on the cone, the Saturation (second channel of HSV, called Chroma in the image) is the distance to the center of the cone and the Value (third channel of HSV) is the height on the cone.
The Hue channel is usually defined between 0-360 and starts with red at 0 (In the case of 8 bit images, OpenCV use the 0-180 range to fit a unsigned char as stated in the documentation). But the thing is, two pixels of value 0 and 359 are really really close together in color. It can be seen more easily when flattening the HSV cone by taking only the outer surface (when Saturation is maximal):
Even if these values are perceptually close (perfectly red at 0 and red with a little tiny bit of purple at 359), these two values are far apart. This is the cause of the "artifacts" you describe in the Hue channel. When OpenCV shows it to you in grayscale, it mapped black to 0 and white to 359. They are, in fact, really similar colors, but when mapped in grayscale, are displayed too far apart. There are two ways to circumvent this counter-intuitive fact: you can re-cast the H channel into RGB space with a fixed saturation and value, which will show a closer representation to our perception. You could also use another color space based on perception (such as the Lab color space) which won't give you these mathematical side-effects.
The reason why these artifact patches are square are explained by Boyko Peranov. The JPEG compression works by replacing pixels by bigger squares that approximates the patch it replaces. If you put the quality of the compression really low when you create the jpg, you can see these squares appears even in the RGB image. The lower the quality, the bigger and more visible are the squares. The mean value of these squares is a single value which, for tints of red, may end up being between 0 and 5 (displayed as black) or 355 and 359 (displayed as white). That explains why the "artifacts" are square-shaped.
We may also ask ourselves why are there more JPEG compression artifacts visible in the hue channel. This is because of chroma subsampling, where studies based on perception showed that our eyes are less prone to see rapid variations in color than rapid variations in intensity. So, when compression, JPEG deliberately loses chroma information because we won't notice it anyway.
The story is similar for the saturation (your bottom left image) white varying spots. You're describing pixels nearly black (on the tip of the cone). Hence, the Saturation value could vary much but won't affect the color of the pixel much: it will always be near black. This is also a side-effect of the HSV color space not being purely based on perception.
The conversion between RGB (or BGR for OpenCV) and HSV is (in theory) lossless. You can convince yourself of this: re-convert your HSV image into the RGB one, you get the exact same image as you began with, no artifacts added.
You are working with a lossy compressed image, hence the rectangular artifacts. With video you have low exposition time, can have bandwidth limitations, etc. So the overall picture quality degrades. You can:
Use a series of still shots by using Capture instead of VideoCapture or
Extract 5-10 video frames, and average them.