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)
Related
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));
I wanna calculate the perceived brightness of an image and classify the image into dark, neutral and bright. And I find one problem here!
And I quote Lakshmi Narayanan's comment below. I'm confused with this method. What does "the average of the hist values from 0th channel" mean here? the 0th channel refer to gray image or value channel in hsv image? Moreover, what's the theory of that method?
Well, for such a case, I think the hsv would be better. Or try this method #2vision2. Compute the laplacian of the gray scale of the image. obtain the max value using minMacLoc. call it maxval. Estimate your sharpness/brightness index as - (maxval * average V channel values) / (average of the hist values from 0th channel), as said above. This would give you certain values. low bright images are usually below 30. 30 - 50 can b taken as ok images. and above 50 as bright images.
If you have an RGB color image you can get the brightness by converting it to another color space that separates color from intensity information like HSV or LAB.
Gray images already show local "brightness" so no conversion is necessary.
If an image is perceived as bright depends on many things. Mainly your display device, reference images, contrast, human...
Using a few intensity statistics values should give you an ok classification for one particular display device.
I have a photo editing app that is built around Brad Larson's amazing
GPUImage framework.
I need a way to analyze an image's histogram so i can return it's range.
Meaning the real range of "activity".
I need this to improve a tool i have in the app that controls the RGB composite curve.
Is there a way to analyze or retrieve hard numbers from the histogram filter in GPUImage ? any other way to do it?
As I document in the Readme.md for the GPUImageHistogramFilter:
The output of this filter is a 3-pixel-high, 256-pixel-wide image with
the center (vertical) pixels containing pixels that correspond to the
frequency at which various color values occurred. Each color value
occupies one of the 256 width positions, from 0 on the left to 255 on
the right. This histogram can be generated for individual color
channels (kGPUImageHistogramRed, kGPUImageHistogramGreen,
kGPUImageHistogramBlue), the luminance of the image
(kGPUImageHistogramLuminance), or for all three color channels at once
(kGPUImageHistogramRGB).
To get the numerical values for the histogram, have the GPUImageHistogramFilter output to a GPUImageRawDataOutput and grab bytes from that. The result will be a 256x3 (width, height) array of 0-255 values indicating the intensity at each color component. You can ignore the first and last rows, as the values are only present in the center row.
From there, you can analyze the histogram obtained by this operation.
I am trying to work out the difference between Erosion and Dilation for binary and grayscale images.
As far as I know, this is erosion/dilation for binary images...
Erosion: If every pixel corresponding to an SE index that has 1 is a 1, output a 1. Otherwise 0.
Dilation: If at least one pixel corresponding to an SE index that has 1 is a 1, output a 1. Otherwise 0.
My question is, how does this work for 16-bit (0, 65535) grayscale images?
So what we have to do is to create an structual Element, that could be for example:
The formula says for dilation says:
image http://utam.gg.utah.edu/tomo03/03_mid/HTML/img642.png
and for erosion:
image http://utam.gg.utah.edu/tomo03/03_mid/HTML/img643.png
that means with have to take the maximum or minumum of each kernel values in the image and add 10 to it. If we have for example:
it goes to using dilation:
How you can see you just look at pixel position x,y take the center and add 10 to it. Then you check the neighbors if the computed value is the maximum. If it is a new maximum the pixel value get replaced, when not the pixel value stays. Hope it is clear for erosion you just take the minimum.
I am working with opencv 2.4 and numpy. I would like to open an image and get all the information about it (8 bit - if its RGB-BGR etc) and also try to change the color space.
I have this code:
if __name__ == '__main__':
img = cv2.imread('imL.png')
conv= cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
cv2.imwrite('lab.png', conv )
When I open the file lab.png I get the image with different colors!
I check the value of BGR to LAB in: http://www.brucelindbloom.com/
For this I would like to know all the information about one image.
That rigtht you will get a different image colour because imwrite() saves file in the format specified (PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with ‘BGR’ channel order). images can be saved using this function. imwrite() doesn't know the format LAB to save image as it always expect the image in BGR.
If the format, depth or channel order is different, use Mat::convertTo() , and cvtColor() to convert it before saving.
Lab is another color space, like the BGR color space which is gained from cv2.imread(). It just like you convert temperature from Fahrenheit to Celsius.
32 Fahrenheit and 0 Celsius is the same temperature but in different unit.
cv2.imwrite() dose not know if the values are in BGR color space or not. When it get a 3 dimension array, it assume that it is a BGR color space while your conv variable contains Lab color space. This is why your color of your image is changed.
For your information, Each layer of BGR color space contains blue, green and red colors while layers of Lab contains lightness (0-100), a* and b* respectively. For more information, please see "Lab color space" in Wikipedia.