While plotting single channel image (i.e. while plotting grayscale images) when using Python it does not plot in gray-scale.
Example: expected output, after converting a coloured image using COLOR_BGR2GRAY from open cv :
But, the output obtained is:
Can anyone help me find out, what is the exact issue?
Upon researching, I found out that, the issue is actually not with open cv, but it is with matplotlib package. While displaying the image, the matplotlib package uses a colormap and hence it has to be explicitly set to gray, using :
plt.imshow(image, cmap="gray")
Related
I'm using a custom library to transform a 1D signal to a 2D representation. The output it's printed through plt.imshow(), used by a function inside of the library. I have the result but i don't want to save the picture locally. There is a way to get as a PIL image what is being used by plt.imshow?
EDIT: The answer is yes, as #Davide_sd is pointing out ax.images[idx].get_array() can be used to retrieve the data
You can use ax.images[idx].get_array() to retrieve the data, after which you can use it on PIL. ax is the axes where the image has been plotted. idx is the index of the image you are interested: if you have plotted a single image, then idx=0.
I have a uint16 3-dim numpy array reppresenting an RGB image, the array is created from a TIF image.
The problem is that when I import the original image in QGIS for example is displayed correctly, but if I try to display within python (with plt.imshow) the result is different (in this case more green):
QGIS image:
Plot image:
I think it is somehow related to the way matplotlib manages uint16 but even if I try to divide by 255 and convert to uint8 I can't get good results.
Going by your comment, the image isn't encoded using an RGB colour space, since the R, G and B channels have a value range of [0-255] assuming 8 bits per channel.
I'm not sure exactly which colour space the image is using, but TIFF files generally use CMYK which is optimised for printing.
Other common colour spaces to try include YCbCr (YUV) and HSL, however there are lots of variations of these that have been created over the years as display hardware and video streaming technologies have advanced.
To convert the entire image to an RGB colour space, I'd recommend the opencv-python pip package. The package is well documented, but as an example, here's how you would convert a numpy array img from YUV to RGB:
img_bgr = cv.cvtColor(img, cv.COLOR_YUV2RGB)
When using plt.imshow there's the colormap parameter you can play with, try adding cmap="gray" so for example
plt.imshow(image, cmap="gray")
source:
https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.imshow.html
If I try to normalize the image I get good results:
for every channel:
image[i,:,:] = image[i,:,:] / image[i,:,:].max()
However, some images appear darker than others:
different images
I am trying to save a grayscale image using matplotlib savefig(). I find that the png file which is saved after the use of matplotlib savefig() is a bit different from the output image which is showed when the code runs. The output image which is generated when the code is running contains more details than the saved figure.
How can I save the output plot in such a manner that all details are stored in the output image?
My my code is given below:
import cv2
import matplotlib.pyplot as plt
plt.figure(1)
img_DR = cv2.imread(‘image.tif',0)
edges_DR = cv2.Canny(img_DR,20,40)
plt.imshow(edges_DR,cmap = 'gray')
plt.savefig('DR.png')
plt.show()
The input file (‘image.tif’) can be found from here.
Following is the output image which is generated when the code is running:
Below is the saved image:
Although the two aforementioned images denote the same picture, one can notice that they are slightly different. A keen look at the circular periphery of the two images shows that they are different.
Save the actual image to file, not the figure. The DPI between the figure and the actual created image from your processing will be different. Since you're using OpenCV, use cv2.imwrite. In your case:
cv2.imwrite('DR.png', edges_DR)
Use the PNG format as JPEG is lossy and would thus give you a reduction in quality to promote small file sizes. If accuracy is the key here, use a lossless compression standard and PNG is one example.
If you are somehow opposed to using OpenCV, Matplotlib has an equivalent image writing method called imsave which has the same syntax as cv2.imwrite:
plt.imsave('DR.png', edges_DR, cmap='gray')
Note that I am enforcing the colour map to be grayscale for imsave as it is not automatically inferred like how OpenCV writes images to file.
Since you are using cv2 to load the image, why not using it also to save it.
I think the command you are looking for is :
cv2.imwrite('gray.jpg', gray_image)
Using a DPI that matches the image size seems to make a difference.
The image is of size width=2240 and height=1488 (img_DR.shape). Using fig.get_size_inches() I see that the image size in inches is array([7.24, 5.34]). So an appropriate dpi is about 310 since 2240/7.24=309.4 and 1488/5.34=278.65.
Now I do plt.savefig('DR.png', dpi=310) and get
One experiment to do would be to choose a high enough DPI, calculate height and width of figure in inches, for example width_inch = width_pixel/DPI and set figure size using plt.figure(figsize=(width_inch, height_inch)), and see if the displayed image itself would increase/decrease in quality.
Hope this helps.
I would like to make a QT based GUI program which overlays a heatmap on an image from 20fps streaming FHD video.
The target image looks like this
(Additionally, a colorbar beside an overlayed image shall also be displayed.)
The size of heatmap source for each image is 100x40, and therefore interpolation for FHD(1920x1080) is needed per frame.
(FYI, The min and max values of heatmap source are around 10 and 100000, respectively.)
First of all, I used cv2.VideoCapture function in Opencv to get images from video. And then, I googled some examples to combine image and heatmap using Matplotlib such as:
https://github.com/durandtibo/heatmap
Heatmap on top of image
Overlay an image segmentation with numpy and matplotlib
The problem that I faced is processing speed to meet 20fps for FHD resolution.
It seemed that Opencv is more adequete rather than Matplotlib for real-time processing.
(I couldn't find the good way to show heatmap and colorbar using Pyqtgraph even though it provides high speed.)
So, I searched another way using cv2.applyColorMap and cv2.resize.
It looks like cv2.applyColorMap function doesn't automatically adjust the range of values unlike imshow function in Matplotlib, and therefore the color of result image is strange.
Moreover, Opencv image needs to be adopted to QtWidget using QtGui.QImage and QtGui.QPixmap which results additional delay.
Finally, the overall processing time of the method I searched can not meet the requirement.
Please show me the way for the solution.
Thanks in advance.
I know some some people have asked this problem before, but the solutions they provided seems do not work to mine.
I just give the links below and maybe they are helpful for you.
Matplotlib plots: removing axis, legends and white spaces
How to set the margins for a matplotlib figure?
As described in the problem title, I use following code to handle this problem.
plt.imshow(img)
plt.axis('off')
plt.savefig('seg_missi5.png', bbox_inches='tight')
plt.show()
And I want the saved image with no white spaces and the same size with the original one.
I have tried using print img.shape to see the size of img, it shows (342, 548, 3), which is the same as the original one, but the saved image, it don't. It's size if 438 x 675, which is bigger and has white spaces.
Arguably, matplotlib might not be the best tool to achieve this (although it's certainly possible). I propose the Python Image Library as a substitute. Using this library, you can save your image like this:
from PIL import Image
im = Image.fromarray(np.uint8(img))
im.save('outfile.png', "PNG")
You can try using pad_inches=0
plt.savefig('seg_missi5.png', bbox_inches='tight', pad_inches=0)
Default size is 0.1. You can get more information from http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.savefig