conv2 in octave showing a white image [duplicate] - image-processing

I have computed an image with values between 0 and 255. When I use imageview(), the image is correctly displayed, in grey levels, but when I want to save this image or display it with imshow, I have a white image, or sometimes some black pixels here and there:
Whereas with imageview():
Can some one help me?

I think that you should use imshow(uint8(image)); on the image before displaying it.

Matlab expects images of type double to be in the 0..1 range and images that are uint8 in the 0..255 range. You can convert the range yourself (but change values in the process), do an explicit cast (and potentially loose precision) or instruct Matlab to use the minimum and maximum value found in the image matrix as the white and black value to scale to when visualising.
See the following example with an uint8 image present in Matlab:
im = imread('moon.tif');
figure; imshow(im);
figure; imshow(double(im));
figure; imshow(double(im), []);
figure; imshow(im2double(im));

Related

Converting colored image to grayscale

I am working on processing images that consists of colors that have the same grayscale. In other words, each image is colored with random colors that have the same gray value.
When I converted the image using (rgb2grey() from skimage or cv2.cvtColor() from OpenCV), the resulted image has only one gray value (or slightly difference gray values (unperceivable by human eyes). Therefore, the resulted image details unrecognizable.
My questions are:
What are the best way to do before converting these images to grayscale ones? (Please note the colors of these images are not fixed)
Are there any color combinations for which the color-gray conversion algorithms won't work?
How about using YCbCr?
Y is intensity, Cb is the blue component relative to the green component and Cr is the red component relative to the green component.
So I think YCbCr can differentiate between multiple pixels with same grayscale value.

uint16 image to float - histogram stretching?

I have an uint16 satellite image whose values range from 0 to 3458 and its histogram is like this:
original histogram
I want to convert the image to float (range 0-1) but of course, I can simply divide everything by 3458 otherwise I will get a very dark image (because most pixels are below 500 as you can see from the histogram).
I would like to get a histogram like this:
new histogram
but I don't really know how to do it.
First of all you should convert your image type to float precision. If you are using MATLAB the function that can help you could be im2double().
Secondly, are you using imhist() function to show your histogram? If yes, It can easily get the range of bins you want to show your histogram.

Visualizing RGB bands of RGBN image

I have an RGBN band .tif satellite image of PlanetScope which I would like to preprocess for a neural network. When I view the image in QGIS I get a nice RGB image, however when importing as a numpy array the image is very light. Some information on the image:
Type of the image : <class 'numpy.ndarray'>
Shape of the image : (7327, 7327, 5)
Image Height 7327
Image Width 7327
Image Shape (7327, 7327, 5)
Dimension of Image 3
Image size 268424645
Maximum RGB value in this image 65535
Minimum RGB value in this image 1
The image is uint16 type. The last band (pic[:,:,5]) only shows a singular value (65535) in all instances. Hence, I think this band should be removed leaving the RGBN bands, of which the information is as follows:
Type of the image : <class 'numpy.ndarray'>
Shape of the image : (7327, 7327, 4)
Image Height 7327
Image Width 7327
Image Shape (7327, 7327, 4)
Dimension of Image 3
Image size 214739716
Maximum RGB value in this image 19382
Minimum RGB value in this image 1
The maximum value (19382) of the RGBN image seems pretty low knowing that the range of uint16 images is 0-65535. Subsequently the function 'skimage.io.imshow(image)' shows a nearly white image. I do not understand why QGIS is able to show the image properly in real color but python does not.
The image is loaded by means of pic = skimage.io.imread("planetscope_20180502_43.tif")
I have tried scaling the image with img_scaled = pic / pic.max() and converting it to uint8 before viewing the image with img_as_ubyte(pic) without success. I view the image with skimage.io.imshow(pic).
If necessary the image can be downloaded here. I incorporate the image because somehow it seems not possible to import the image using certain packages (Tifffile for example does not work on this tif file).
The max values of the RGB channels are lower than that of the N channel:
>>> pic.max(axis=(0,1))
array([10300, 7776, 11530, 19382, 65535], dtype=uint16)
But look at the mean values of the RGB channels: they are much smaller than max/2:
>>> pic.mean(axis=(0,1))
array([ 439.14001492, 593.17588875, 542.4638124 , 3604.6826063 ,
65535. ])
You have a high dynamic range (HDR) image here and want to compress its high range to 8 bits for displaying. A linear scaling with the maximum value won't do as the highest peaks are an order of magnitude higher than the average image values. Plotting the histogram of the RGB values:
If you do a linear scaling with some factor that's a bit above the mean and just disregard clipping the rest (now overexposed) values you can display it to see you have valid data:
rgb = pic[..., :3].astype(np.float32) / 2000
rgb = np.clip(rgb, 0.0, 1.0)
But to get a proper image, you will need to look into what the camera response of your data is, and how these HDR images are usually compressed into 8 bits for displaying (I'm not familiar with satellite imaging).
Thank you w-m, I was able to built on that and figured it out. Since w-m already did a neat job to elaborate on the problem, I will just leave the code here that I wrote to resolve the issue:
for i in range(0,4):
min_ = int(np.percentile(image[:,:,i],2))
max_ = int(np.percentile(image[:,:,i],98))
np.maximum(image[:,:,i])
np.minimum(image[:,:,i])
image[:,:,i] = np.interp(image[:,:,i], image[:,:,i].min(), image[:,:,i].max(), (0,255))
image_8bit_scaled = skimage.img_as_ubyte(image)

Convert to grayscale and reduce the size

I am trying to develop an OCR in VB6 and I have some problems with BMP format. I have been investigating the OCR process and the first step is to convert the image in "black and white" with a threshold. The conversion process is easy to understand and I have done it. However, I'm trying to reduce the size of the resulting image because it uses less colors (each pixel only has 256 possible values in grayscale). In the original image I have 3 colors (red, green and blue) but now I only need one color (the value in grayscale). In this moment I have achieved the conversion but the resulting grayscale images have the same size as the original color image (I assign the same color value in the three channels).
I have tried to modify the header of the BMP file but I haven't achieved anything and now I don't understand how it works. For example, if I convert the image with paint, the offset that is specified in the header changes its value. If the header is constant, why does the offset change its value?.
The thing is that a grey-scale bitmap image is the same size as a color bitmap image because the data that is used to save the grey colors takes just as much space as the color.
The only difference is that grey is just 3 times that same value. (160,160,160) for example with color giving something like (123,200,60). The grey values are just a small subset of the RGB field.
You can trim down the size after converting to grey-scale by converting it from 24 bit to 16 bit or 8-bit for example. Although it depends on what you are using to do the conversion whether that is already supplied to you. Otherwise you'll have to make it yourself.
You can also try using something else than BMP images. PNG files are lossless too, and would even save space with the 24 bit version. Image processing libraries usally give you several options as output formats. Otherwise you can probably find a library that does this for you.
You can write your own conversion in a "lockbits" method. It takes a while to understand how to lock/unlock bits correctly, but the effort is worth it, and once you have the code working you'll see how it can be applied to other scenarios. For example, using an lock/unlock bits technique you can access the pixel values from a bitmap, copy those pixel values into an array, manipulate the array, and then copy the modified array back into a bitmap. That's much faster than calling GetPixel() and SetPixel(). That's still not the fastest image manipulation code one can write, but it's relatively easy to implement and maintain the code.
It's been a while since I've written VB6 code, but Bob Powell's often has good examples, and he has a page about lock bits:
https://web.archive.org/web/20121203144033/http://www.bobpowell.net/lockingbits.htm
In a pinch you could create a new Bitmap of the appropriate format and call SetPixel() for every pixel:
Every pixel (x,y) in your 24-bit color image will have a color value (r,g,b)
After conversion to a 24-bit gray image, each pixel (x,y) will have a three equal values for each color channel; that can be expressed as (n,n,n) as Willem wrote in his reply. If all three colors R,G,B have the same value, then you can say that color value is the "grayscale" value of that pixel. This is the same shade of gray that you will see in your final 8-bit bitmap.
Call SetPixel for each pixel (x,y) in a newly created 8-bit bitmap that is the same width and height as the original color image.

What is a good way of Enhancing contrast of color images?

I split color image for 3 channels and made a contrast enhancement of each channel.
Then merged them together, I like the image at the result, but it has different colors.
Black objects became yellow and so on...
EDIT:
The algorithm I used is to calculate the 5th percentile and the 95th percentile
as min and max values, and then expand the values of image so that it will have min and max values as 0 and 255. If there is a better approach please tell me.
When doing contrast enhancement in color images, it is a good idea to only adjust the luminance (brightness) and leave the color information alone. This requires a colorspace conversion from RGB to something like YUV. In this colorspace, the Y component is similar to a grayscale version of the image, while the other components provide the color. This effectively allows you to adjust contrast (by running your algorithm on just the Y component) without distorting the color information. Finally, you can convert back to RGB.
Use CLAHE algorithm. openCV has an implementation of it: cv::createCLAHE()

Resources