Changing image bit depth using matlab - matlab

I want to change 8-bit images' bit depths to 4-bit, 2-bit depths using Matlab.
Source images are 8-bit and jpg files. I wanted to take advantage of png 'BitDepth' parameter, so first I tried to convert images into png format. Then I tried to use this parameter; but I'm getting errors. Also it's OK for me if there's a simple solution using Java libraries.
function [] = changeBitDepth(path, depth)
clear all; close all;
clc;
A = imread(path);
imshow(A);
imwrite(A, '~/Desktop/football.png');
B = imread('~/Desktop/football.png');
imwrite(B, '~/Desktop/bitDepthChanged.png', 'BitDepth', depth);
imfinfo('~/Desktop/bitDepthChanged.png');

That's because you can only have 8 or 16 bit images for standard color images. You can have different bit depth for e.g. indexed images, or grayscale images (wiki description of png).
Indexed color PNGs are allowed to have 1, 2, 4 or 8 bits per pixel by the standard; grayscale images with no alpha channel allow for 1, 2, 4, 8 or 16 bits per pixel. Everything else uses a bit depth per channel of either 8 or 16.
You could do something like this:
% convert to indexed image
[IND,map] = rgb2ind(A,32);
% save indexed png
imwrite(IND, map, 'test.png', 'bitdepth', 4);
Look here to know how matlab deals with indexed images.

Related

Imshow in Matlab returns black image [duplicate]

This question already has answers here:
16-bit grayscale TIFF
(2 answers)
Closed 1 year ago.
I want to display a satellite image (16bit) that contains 4 bands with intensity levels: red, greens, blue and nir. However, I just want to display the first 3 bands. I use the following code:
RGB=imread('IMG_PHR1B_MS_202106020751594_ORT_5893575101-2_R1C1.TIF');
subset_RGB=RGB(1550:3238,343:1250,1:3);
figure(1)
imshow(subet_RGB)
impixelinfo
The pixels show clearly different values, but the image is completely black.
values range from:
red: 473-4152
green:599-4256
blue:507-3737
I transformed this image to HSV (because I also need this).
normal=im2double(subset_RGB);
hsv=rgb2hsv(normal);
imshow(hsv)
This image does result in a colour image.
I maybe thought it was because hsv is double and subset_RGB is 16-bit. so I tried the following:
test=im2double(subset_RGB)
imshow(test)
I also tried imagesc as suggested, but results in black image:
figure(2)
imagesc(subset_RGB)
How can I display the original image in true colours?
To display an RGB image using imshow, you have to rescale it from 0 to 255. I do not know what is the original bit depth of your image (even though it is saved with 16 bits, the actual bit depth may be smaller). I will assume it is 13 bits, as it is the next power of two higher than the values you have shown.
rescaled_img = uint8(double(subset_RGB) / (2^(13-8)));
imshow(rescaled_img);
Note that the colours may be off or too dark if the bit depth is wrong. An alternative, instead of dividing by 8192, you can divide by the maximum in the image. In that case, use:
rescaled_img = uint8(256 * double(subset_RGB) / max(subset_RGB, [], 'all'));
imshow(rescaled_img);

Single channel png displayed with colors

I'm checking out the ground truth segmentation masks of the pascal voc 2012 dataset. These are single channel 8-bit uint png files. However when I open these images in either the file browser (nautilus) or the image viewer (eog) they are displayed in colors.
Shouldn't it be displayed in grayscale?
When I store an image as single channel 8-bit uint png file using Matlab, it is displayed in grayscale as expected. What is the difference are there different types of png files?
How can I store it such that my image viewer displays them in colors?
This is the original single channel png:
This is the result after imread and imwrite. Note that NO channel has been added / removed:
Your image files contain indexed images, with an M-by-N index matrix and a P-by-3 colormap matrix. How can you tell? You need to get the second output from imread when loading your images:
[img, cmap] = imread('zuIra.png');
if isempty(cmap)
% Process data as a grayscale or RGB image
else
% Process data as an indexed image
end
If cmap is empty, your data is either an M-by-N grayscale intensity image or an M-by-N-by-3 Truecolor RGB image. Otherwise, you're dealing with an indexed color image, and will have to use both pieces of data in any processing of your image, such as viewing it with imshow:
imshow(img, cmap);
Or when resaving the data with imwrite:
imwrite(img, cmap, 'outfile.png');
If you would rather deal with a single image data matrix (which can make processing easier in some cases), you can convert the indexed image data and associated colormap into an RGB image with ind2rgb:
imgRGB = ind2rgb(img, cmap);
You are dealing with an 1 to 8 bits (variable) per pixel PNG with indexed colors.
When a format uses this technique, color information is not directly stored into the the image pixel data, but in a separate piece of data called palette. A palette can be defined as a predefined array of colors in which each element defines the trichromatic representation (RGB) of a specific color (8 bits per channel, for a total of 24 bits).
The image pixel data does not contain the full specification of a color in the RGB form, but only the indices to the palette colors. Of course, the palette must contain one entry for each pixel color present in the image.
This approach can be seen as a form of compression, in which only a limited set of colors is available in order to save up memory/storage and speed up the display of the image.
Long story short, the result of your imread call is not returning you the color information of the image. Your array contains the indices to the PNG palette elements.
Example
Let's say that you have n indexed PNG that has a width of 3 pixels and a height of 1 pixel. The first pixel is pure red, the second pixel is pure green and the third pixel is pure blue.
In the PNG binary data, the PLTE chunk will contain the following color definitions:
[255 0 0] % Pure Red
[0 255 0] % Pure Green
[0 0 255] % Pure Blue
and the IHDR chunk will define a single channel with the following data:
0 1 2
% 0 = index to the first palette color, pure red
% 1 = index to the second palette color, pure green
% 2 = index to the third palette color, pure blue

How to know the depth value of 24bit depth images in matlab

I am trying to deal with 24bit depth images from NYU Hand dataset in MATLAB.
When i tried to read images as below in MATLAB
img = imread('synthdepth_1_0006969.png');
the form of the variable( img) is 480x640x3 uint8.
My question is, in this case, how do i know the depth value from that?
When I read 8bit or 16bit images in MATLAB, each pixel show the depth value. But
in 24bit case, I don't know how to deal with it...
Thank you for reading my question.
Notice that the image data is 3 dimensional, with the third dimension having a size of 3. That third dimension encodes the red, green, and blue color planes in a Truecolor image. Three uint8 (i.e. unsigned 8-bit integer) color values equates to 24 bits of total color information per pixel.

comparing images pixel by pixel

I am working on some images. I am given an abc.tif image ( color image) . I read it as follows:
Mat test_image=imread("abc.tif",IMREAD_UNCHANGED);
I perform some operations on it and convert it into some binary image (using threshold) containing only two values 0 and 255 which are stored in img image where img is created as following:
Mat img(584,565,CV_8UC1); %//(so now img contains only 0 and 255)
I save this image using imwrite("myimage.jpg",img);
I want to compare the myimage.jpg image with another binary image manual.gif pixel by pixel to check whether one image is duplicate of another but as you can notice the problem is OpenCv doesnot support .gif format so I need to convert it into .jpg and because of that the image changes and now both the images will be concluded as different images may be even though they are same. What to do now?
Actually I am working on retinal blood vessel segmentation and these images are found in the DRIVE database.
I am given these images. Original image:
I perform some operations on it and extract blood vessels from it and then create a binary image and store in some Mat variable img as discussed earlier. Now I have got another image (.gif image) which I cannot load as shown below:
Now I want to compare my img image (binary) with the given .gif image (above) which I cannot load.
Use ImageMagic for converting your .gif to .PNG in batch mode. You could also convert it on the fly using system("convert img.gif img.png") call.
I'm not sure, if pixel comparison will give you good result. An offset shift of the same image will result in bad match.
EDIT As an idea. Maybe calculating centers of gravity and shifting/rotating both images to have the same origin may help here.
Consider using moments, freeman chain or other mode robust shape comparison methods.
first off you will want to use the images in the same format as each other #Adi mentioned jpg is lossy in the comments which is correct so shouldn't be used until possibly after any work is done. MATLAB - image conversion
you will also want the images to be of the same size. you can compare them using the size function and then pad them to add pixels to make the dimensions the same. the padding can always be removed later, just watch how the padding is added so as not to affect your operations.
you will also need to look into rotations, consider putting the image into the frequency domain and rotate the image to align the spectrum's.
below is a simple pixel comparison code, pixel comparison is not particularly accurate for comparing. even the slightest miss alignment will cause false negatives or false positives.
%read image
test_image1 = imread('C:\Users\Public\Pictures\Sample Pictures\Desert.jpg');
test_image2 = imread('C:\Users\Public\Pictures\Sample Pictures\Hydrangeas.jpg');
%convert to gray scale
gray_img1 = rgb2gray(test_image1);
gray_img2 = rgb2gray(test_image2);
% threshold image to put all values greater than 125 to 255 and all values
% below 125 to 0
binary_image1 = gray_img1 > 125;
binary_image2 = gray_img2 > 125;
%binary image to size to allow pixel by pixel checking
[row, col] = size(binary_image1);
% initialize the counters for similar and different pixelse to zero
similar = 0;
different = 0;
%two loops to scan through all rows and columns of the image.
for kk = 1 : row
for yy = 1 : col
%using if statement with isequal function to compare corresponding
%pixel values and count them depending ont he logical output of
%isequal
if isequal(binary_image1(kk,yy), binary_image2(kk,yy))
similar = similar + 1;
else
different = different + 1;
end
end
end
% calculate the percentage difference between the images and print it
total_pixels = row*col;
difference_percentage = (different / total_pixels) * 100;
fprintf('%f%% difference between the compared images \n%d pixels being different to %d total pixels\n', difference_percentage, different, total_pixels )
% simple supbtraction of the two images
diff_image = binary_image1 - binary_image2;
%generate figure to show the original gray and corresponding binary images
%as well as the subtraction
figure
subplot(2,3,1)
imshow(gray_img1);
title('gray img1');
subplot(2,3,2)
imshow(gray_img2);
title('gray img2');
subplot(2,3,4)
imshow(binary_image1);
title('binary image1');
subplot(2,3,5)
imshow(binary_image2);
title('binary image2');
subplot(2,3,[3,6])
imshow(diff_image);
title('diff image');

14 Bit RGB to YCrCb

I have a 14 bit image that I like to convert to YCrCb color space. As far as I know the conversions are written for 8-bit images. For instance when I use matlab function rgb2ycrcb and I convert it back to rgb then it would be all whites. It is very important for me to not lose any information. What I want to do is to separate luminance from chroma and do some process and convert it back to RGB.
The YCbCr standard to convert quantities from the RGB colour space was specifically designed for 8-bit colour channel images. The scaling factors and constants are tailored so that the input is a 24-bit RGB image (8-bits per channel. BTW, your notation is confusing. Usually you use xx-bit RGB to represent how many bits in total that is required to represent the image).
One suggestion I could make is to rescale your channels independently so that they go from [0-1] for all channels. rgb2ycbcr can accept floating point inputs so long as they're in the range of [0-1]. Judging from your context, you have 14 bits representing each colour channel. Therefore, you can simply do this, given that your image is stored in A and the output will be stored in B:
B = rgb2ycbcr(double(A) / (2^14 - 1));
You can then process your chroma and luminance components using the output of rgb2ycbcr. Bear in mind that the components will also be normalized between [0-1]. Do your processing, then convert back using ycbcr2rgb, then rescale your outputs by 2^14 - 1 to bring your image back into 14-bit RGB per channel. Assuming Bout is your output image after your processing in the YCbCr colour space, do:
C = round((2^14 - 1)*ycbcr2rgb(Bout));
We round as this will most likely provide floating point values, and your image colour planes need to be unsigned integers.