image plotted using matplotlib seems to have different colors than original JPEG image - image

The screenshot below compares the same image plotted using matplotlib on the left and Mac preview on the right.
Code for plotting the image using matplotlib is also fairly simple.
import matplotlib.pyplot as plt
import argparse
import skimage
parser = argparse.ArgumentParser(description='Color check.')
parser.add_argument('--image', required=False,metavar="path or URL to image")
args = parser.parse_args()
image = skimage.io.imread(args.image)
plt.imshow(image)
plt.show()
As you can see the colors are visibly different in the two images. Why is this happening and which one should I trust to be the correct color representation?
EDIT:
I plotted the image using opencv's imshow and it looks fine.
and here is the code:
import argparse
import cv2
windowName = "image"
cv2.namedWindow(windowName,cv2.WINDOW_NORMAL)
cv2.resizeWindow(windowName, 600,600)
parser = argparse.ArgumentParser(description='Color check.')
parser.add_argument('--image', required=False,metavar="path or URL to image")
args = parser.parse_args()
image = cv2.imread(args.image)
cv2.imshow(windowName, image)
cv2.waitKey(0)

The disagreement probably comes from the difference in colorspace used by the two programs. While Mac Preview is colorspace aware, and therefore should display images using the proper colorspace in which they are created/tagged, matplotlib uses the sRGB colorspace.
I would say that the color representation used by Mac Preview is most likely the one also used by the creator of the image, therefore the one I would pick.

Related

kivy image and PIL image

I can read an image using kivy camera. I wish to interpret a QR code in that image using code similar to this
texture = self.cameraObject.texture
size=texture.size
frame=texture.pixels
pil_image = Image.frombytes(mode='RGBA', size=size,data=frame)
pix=numpy.array(pil_image)
im=Image.fromarray(pix)
qrCodeDetector =cv2.QRCodeDetector()
decodedText, points, _ = qrCodeDetector.detectAndDecode(pix)
Kivy camera allows me to scan an image but to use the QR detector the image has to be converted to a numpy array
I have an import and then a class that starts off
from kivy.uix.image import Image
class KivyCamera(Image):
def __init__(self, **kwargs):
super(KivyCamera, self).__init__(**kwargs)
self.capture = None
# and so on
The program runs but methods that are in the PIL Image class are not available. For example Image.frombytes and Image.fromarray which is needed to convert an image to another.
Changing the Image import to
from PIL import Image
The program crashes with error message
class KivyCamera(Image):
TypeError: module.init() takes at most 2 arguments (3 given)
How do I either do the image conversion using the kivy Image which seems impossible or how do I get the init module to accept the PIL Image class?
You can import both Image classes like this:
from kivy.uix.image import Image
from PIL import Image as Pimage
Then, wherever you want to use the PIL Image, use Pimage:
pil_image = Pimage.frombytes(mode='RGBA', size=size,data=frame)

PIL output picture bigger than input

I am currently working on an automatic script for changing contrast on all the pictures inside a folder, using PIL (python). The problem is each output picture is bigger than input one... Here is my script:
from PIL import Image, ImageEnhance
import piexif
path="C:/User/pictures/"
all_files=["picture1.jpg", "picture2.jpg", "picture3.jpg"]
for i in range(len(all_files)):
im_path=all_files[i]
im = Image.open(path+im_path)
#load exif data
exif_dict = piexif.load(im.info['exif'])
exif_bytes = piexif.dump(exif_dict)
dpi = im.info["dpi"]
#image brightness enhancer
contraster = ImageEnhance.Contrast(im)
im_output = contraster.enhance(factor)
im_output.save(new_path+im_path, format="JPEG", quality=100, dpi=dpi, exif=exif_bytes, subsampling=0)
For example, my incoming jpg picture was 8.08Mo, and my new one is 15.8Mo, even if I chose a 0% change of contrast...
Thanks a for answering, have a nice week-end.
You have specified quality=100 against the recommendations of the library authors.
The image quality, on a scale from 0 (worst) to 95 (best). The default is 75. Values above 95 should be avoided; 100 disables portions of the JPEG compression algorithm, and results in large files with hardly any gain in image quality.

How to get image format using skimage?

from PIL import Image
im = Image.open('abc.jpg')
print(im.format) //output: JPEG
How can I write the above code using skimage?
I tried:
import skimage
from PIL import Image
im = skimage.io.imread('abc.jpg')
print(Image.fromarray(im).format)
Did not work for me.
I don't think you can do that with skimage.
When you load an image with PIL like this:
im = Image.open(path)
it returns a PIL Image object which stores the width, height, colourspace, palette and EXIF data.
When you load an image with skimage it just returns a pure Numpy array corresponding to the pixel colours so there is no place to store the format or anything else.

How to read image from in memory buffer (StringIO) or from url with opencv python library

Just share a way to create opencv image object from in memory buffer or from url to improve performance.
Sometimes we get image binary from url, to avoid additional file IO, we want to imread this image from in memory buffer or from url, but imread only supports read image from file system with path.
To create an OpenCV image object with in memory buffer(StringIO), we can use OpenCV API imdecode, see code below:
import cv2
import numpy as np
from urllib2 import urlopen
from cStringIO import StringIO
def create_opencv_image_from_stringio(img_stream, cv2_img_flag=0):
img_stream.seek(0)
img_array = np.asarray(bytearray(img_stream.read()), dtype=np.uint8)
return cv2.imdecode(img_array, cv2_img_flag)
def create_opencv_image_from_url(url, cv2_img_flag=0):
request = urlopen(url)
img_array = np.asarray(bytearray(request.read()), dtype=np.uint8)
return cv2.imdecode(img_array, cv2_img_flag)
As pointed out in the comments to the accepted answer, it is outdated and no longer functional.
Luckily, I had to solve this very problem using Python 3.7 with OpenCV 4.0 recently.
To handle image loading from an URL or an in-memory buffer, I defined the following two functions:
import urllib.request
import cv2
import numpy as np
def get_opencv_img_from_buffer(buffer, flags):
bytes_as_np_array = np.frombuffer(buffer.read(), dtype=np.uint8)
return cv2.imdecode(bytes_as_np_array, flags)
def get_opencv_img_from_url(url, flags):
req = urllib.request.Request(url)
return get_opencv_img_from_buffer(urllib.request.urlopen(req), flags)
As you can see one depends on the other.
The first one, get_opencv_img_from_buffer, can be used to get an image object from an in-memory buffer. It assumes that the buffer has a read method and that it returns an instance of an object that implements the buffer protocol
The second one, get_opencv_img_from_url, generates an image directly from an URL.
The flags argument is passed on to cv2.imdecode,
which has the following constants predefined in cv2:
cv2.IMREAD_ANYCOLOR - If set, the image is read in any possible color format.
cv2.IMREAD_ANYDEPTH - If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
cv2.IMREAD_COLOR - If set, always convert image to the 3 channel BGR color image.
cv2.IMREAD_GRAYSCALE - If set, always convert image to the single channel grayscale image (codec internal conversion).
cv2.IMREAD_IGNORE_ORIENTATION - If set, do not rotate the image according to EXIF's orientation flag.
cv2.IMREAD_LOAD_GDAL - If set, use the gdal driver for loading the image.
cv2.IMREAD_REDUCED_COLOR_2 - If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.
cv2.IMREAD_REDUCED_COLOR_4 - If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
cv2.IMREAD_REDUCED_COLOR_8 - If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
cv2.IMREAD_REDUCED_GRAYSCALE_2 - If set, always convert image to the single channel grayscale image and the image size reduced 1/2.
cv2.IMREAD_REDUCED_GRAYSCALE_4 - If set, always convert image to the single channel grayscale image and the image size reduced 1/4.
cv2.IMREAD_REDUCED_GRAYSCALE_8 - If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
cv2.IMREAD_UNCHANGED - If set, return the loaded image as is (with alpha channel, otherwise it gets cropped).

How to convert an image that is in binary format to something analyzable?

I am studying some simple image processing techniques and came across a question. A task that I want to carry out is to find circles of fixed size in a given image. I'd like to write my own code for learning purposes.
The image that I have is in JPEG format which is in binary, how can I quantize the image so that I can do quantitative analysis on it? I want to calculate the cross-correlation between the template and the image to match the circle.
Thanks a lot for your help.
Can you try converting the jpeg binary into a matrix data-structure?
For ex: in Java you could use code like this to get matrix out of an image
using javax imageio package..
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
File file = new File("file.jpg");
BufferedImage img;
img = ImageIO.read(file);

Resources