`QImage` constructor has unknown keyword `data` - python

Suppose I am taking an image from the webcam using opencv.
_, img = self.cap.read() # numpy.ndarray (480, 640, 3)
Then I create a QImage qimg using img:
qimg = QImage(
data=img,
width=img.shape[1],
height=img.shape[0],
bytesPerLine=img.strides[0],
format=QImage.Format_Indexed8)
But it gives an error saying that:
TypeError: 'data' is an unknown keyword argument
But said in this documentation, the constructor should have an argument named data.
I am using anaconda environment to run this project.
opencv version = 3.1.4
pyqt version = 5.9.2
numpy version = 1.15.0

What they are indicating is that the data is required as a parameter, not that the keyword is called data, the following method makes the conversion of a numpy/opencv image to QImage:
from PyQt5.QtGui import QImage, qRgb
import numpy as np
import cv2
gray_color_table = [qRgb(i, i, i) for i in range(256)]
def NumpyToQImage(im):
qim = QImage()
if im is None:
return qim
if im.dtype == np.uint8:
if len(im.shape) == 2:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_Indexed8)
qim.setColorTable(gray_color_table)
elif len(im.shape) == 3:
if im.shape[2] == 3:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_RGB888)
elif im.shape[2] == 4:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_ARGB32)
return qim
img = cv2.imread('/path/of/image')
qimg = NumpyToQImage(img)
assert(not qimg.isNull())
or you can use the qimage2ndarray library
When using the indexes to crop the image is only modifying the shape but not the data, the solution is to make a copy
img = cv2.imread('/path/of/image')
img = np.copy(img[200:500, 300:500, :]) # copy image
qimg = NumpyToQImage(img)
assert(not qimg.isNull())

I suspect it is erroring out with TypeError: 'data' is an unknown keyword argument because that is the first argument that it encounters.
The linked class reference is for PyQt4, for PyQt5 it links to C++ documentation at https://doc.qt.io/qt-5/qimage.html, but the similarities are clear.
PyQt4:
QImage.__init__ (self, bytes data, int width, int height, int bytesPerLine, Format format)
Constructs an image with the given width, height and format, that uses an existing memory buffer, data. The width and height must be specified in pixels. bytesPerLine specifies the number of bytes per line (stride).
PyQt5 (C++):
QImage(const uchar *data, int width, int height, int bytesPerLine, QImage::Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr)
Constructs an image with the given width, height and format, that uses an existing memory buffer, data. The width and height must be specified in pixels. bytesPerLine specifies the number of bytes per line (stride).
Per the examples at https://www.programcreek.com/python/example/106694/PyQt5.QtGui.QImage, you might try
qimg = QImage(img, img.shape[1], img.shape[0], img.strides[0], QImage.Format_Indexed8)
(without the data=, width=, etc)

Related

Image dimensions swapped after sending through websocket

I'm making an image viewer interface for a camera I have. The backend is written in python and works like this:
Acquire image as numpy array.
Convert numpy array to jpeg.
Convert jpeg to base64 string.
Send string over websocket.
def image_to_bytes(image):
print('into: ', image.shape)
buf = cv2.imencode('.jpg', image)[1]
dec = cv2.imdecode(buf, cv2.IMREAD_COLOR)
print('outa: ', dec.shape)
return base64.b64encode(buf).decode('utf-8')
async def send_image(websocket: WebSocket):
cam = Camera()
for im in cam:
w, h = im.shape[:2]
resized = cv2.resize(im, (w // 4, h // 4), interpolation=cv2.INTER_LINEAR)
await websocket.send_bytes(image_to_bytes(resized))
However when the javascript frontend receives the image the dimensions are swapped which distorts the image.
socket.onmessage = function(event) {
let im = new Image();
const buf = event.data;
im.src = 'data:image/jpeg;base64,' + buf;
im.onload = function() {
context.drawImage(im, 0, 0);
console.log('w=' + im.width + ', h=' + im.height);
};
};
I know that the dimensions are swapped because I checked the dimensions before I encoded the image. Then I decoded it again to make sure the ecoding process didn't swap width and height. Finally I check the dimension on the JS side and width and height are reversed.
Any idea why the dimensions are getting swapped?
From the documentation of OpenCV:
The shape of an image is accessed by img.shape. It returns a tuple of the number of rows, columns, and channels (if the image is color):
Hence instead of w, h = im.shape[:2] you need h, w = im.shape[:2].

Grayscale Image crop and conversion to QPixmap [duplicate]

Suppose I am taking an image from the webcam using opencv.
_, img = self.cap.read() # numpy.ndarray (480, 640, 3)
Then I create a QImage qimg using img:
qimg = QImage(
data=img,
width=img.shape[1],
height=img.shape[0],
bytesPerLine=img.strides[0],
format=QImage.Format_Indexed8)
But it gives an error saying that:
TypeError: 'data' is an unknown keyword argument
But said in this documentation, the constructor should have an argument named data.
I am using anaconda environment to run this project.
opencv version = 3.1.4
pyqt version = 5.9.2
numpy version = 1.15.0
What they are indicating is that the data is required as a parameter, not that the keyword is called data, the following method makes the conversion of a numpy/opencv image to QImage:
from PyQt5.QtGui import QImage, qRgb
import numpy as np
import cv2
gray_color_table = [qRgb(i, i, i) for i in range(256)]
def NumpyToQImage(im):
qim = QImage()
if im is None:
return qim
if im.dtype == np.uint8:
if len(im.shape) == 2:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_Indexed8)
qim.setColorTable(gray_color_table)
elif len(im.shape) == 3:
if im.shape[2] == 3:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_RGB888)
elif im.shape[2] == 4:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_ARGB32)
return qim
img = cv2.imread('/path/of/image')
qimg = NumpyToQImage(img)
assert(not qimg.isNull())
or you can use the qimage2ndarray library
When using the indexes to crop the image is only modifying the shape but not the data, the solution is to make a copy
img = cv2.imread('/path/of/image')
img = np.copy(img[200:500, 300:500, :]) # copy image
qimg = NumpyToQImage(img)
assert(not qimg.isNull())
I suspect it is erroring out with TypeError: 'data' is an unknown keyword argument because that is the first argument that it encounters.
The linked class reference is for PyQt4, for PyQt5 it links to C++ documentation at https://doc.qt.io/qt-5/qimage.html, but the similarities are clear.
PyQt4:
QImage.__init__ (self, bytes data, int width, int height, int bytesPerLine, Format format)
Constructs an image with the given width, height and format, that uses an existing memory buffer, data. The width and height must be specified in pixels. bytesPerLine specifies the number of bytes per line (stride).
PyQt5 (C++):
QImage(const uchar *data, int width, int height, int bytesPerLine, QImage::Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr)
Constructs an image with the given width, height and format, that uses an existing memory buffer, data. The width and height must be specified in pixels. bytesPerLine specifies the number of bytes per line (stride).
Per the examples at https://www.programcreek.com/python/example/106694/PyQt5.QtGui.QImage, you might try
qimg = QImage(img, img.shape[1], img.shape[0], img.strides[0], QImage.Format_Indexed8)
(without the data=, width=, etc)

Converting RGBA Images in a folder and save it to another folder in '.pgm' format

I have a group of RGBA images saved in a folder, my goal is to convert these images into another folder in a pgm format, below is the code:
path1 = file/path/where/image/are/stored
path2 = file/path/where/pgm/images/will/be/saved
list = os.listdir(path1)
for file in listing:
#Transforms an RGBA with channel into an RGB only
image_rgb = Image.open(file).convert('RGB')
#Color separation stains to detect microscopic cells
ihc_hed = rgb2hed(image_rgb)
#Trasnforms the image into a numpy array of the UINT8 Type
cv_img = ihc_hed.astype(np.uint8)
# create color boundaries boundaries detecting black and blue stains
lower = np.array([0,0,0], dtype = "uint8")
upper = np.array([0,0,255], dtype = "uint8")
#calculates the pixel within the specified boundaries and create a mask
mask = cv2.inRange(cv_img, lower, upper)
img = Image.fromarray(mask,'L')
img.save(path2+file,'pgm')
however I get an error stating KeyError: 'PGM', it seems that the 'pgm' format is not in the modes
Thanks for the advice :)
As far as I can see scikit image uses the Python Imaging Library plugin for saving image files. PIL does not support PGM.
Refer to http://effbot.org/imagingbook/decoder.htm for how to write your own file decoder for PIL.
Extract:
import Image, ImageFile
import string
class SpamImageFile(ImageFile.ImageFile):
format = "SPAM"
format_description = "Spam raster image"
def _open(self):
# check header
header = self.fp.read(128)
if header[:4] != "SPAM":
raise SyntaxError, "not a SPAM file"
header = string.split(header)
# size in pixels (width, height)
self.size = int(header[1]), int(header[2])
# mode setting
bits = int(header[3])
if bits == 1:
self.mode = "1"
elif bits == 8:
self.mode = "L"
elif bits == 24:
self.mode = "RGB"
else:
raise SyntaxError, "unknown number of bits"
# data descriptor
self.tile = [
("raw", (0, 0) + self.size, 128, (self.mode, 0, 1))
]
Image.register_open("SPAM", SpamImageFile)
Image.register_extension("SPAM", ".spam")
Image.register_extension("SPAM", ".spa") # dos version

Corrupted image being saved by cv.SaveImage() in opencv

import sys, Image, scipy, cv2, numpy
from scipy.misc import imread
from cv2 import cv
from SRM import SRM
def ndarrayToIplImage (source):
"""Conversion of ndarray to iplimage"""
image = cv.CreateImageHeader((source.shape[1], source.shape[0]), cv.IPL_DEPTH_8U, 3)
cv.SetData(image, source.tostring(), source.dtype.itemsize * 3 * source.shape[1])
return image
"""Main Program"""
filename = "snap.jpeg"
Q = 64
im = imread(filename)
name = filename[:-4]
img = Image.fromarray(im)
if img.size[0] > 200 or img.size[1] > 200:
ratio = img.size[0]/img.size[1]
size = int(ratio*200), 200
img = numpy.array(img.resize(size, Image.ANTIALIAS))
srm = SRM(img, Q)
srm.initialization()
srm.segmentation()
classes, map = srm.map()
"""Converting ndarray to PIL Image to iplimage"""
pil_img = Image.fromarray(map)
cv_img = cv.CreateImageHeader(pil_img.size, cv.IPL_DEPTH_8U, 3)
cv.SetData(cv_img, pil_img.tostring(), pil_img.size[0]*3)
print type(cv_img) ##prints <type 'cv2.cv.iplimage'>
"""Using ndarrayToIplImage function also gives the same error!"""
"""
cv_img if of type iplimage but still gives error while using cv.ShowImage()
or cv.SaveImage().
There is no error displayed. Just the console hangs...
"""
I am using the SRM (Statistical Region Merging) Package available at this page.
I have just changed the example program given in the package. I had to convert the type returned by the SRM package functions to iplimage. There is no error in using the package but somewhere in using opencv functions.
This is the image that is saved after the console closes after hanging.
It used cv.SaveImage().
I tried cv2.imwrite() and I got this as the result:
This is the image that should have been saved. I used scipy.misc.imsave('image.jpg', map) to save this.
Why do you use IplImage and PIL? SRM library read numpy array and you get a numpy array from cv2.imread(image), then if you need to resize yuor image you can use opencv function cv2.resize(...). Finally you can save an image with opencv with cv2.imwrite(...) your code should appear like this:
import sys, cv2, numpy
from SRM import SRM
"""Main Program"""
filename = "snap.jpeg"
Q = 64
img = cv2.imread(filename)
name = filename[:-4]
if img.shape[0] > 200 or img.shape[1] > 200:
ratio = img.shape[0] * 1. / img.shape[1]
size = (int(ratio * 200), 200)
img = cv2.resize(img, size, interpolation=cv2.INTER_LANCZOS4)
srm = SRM(img, Q)
srm.initialization()
srm.segmentation()
classes, srmMap = srm.map() # Map is a python function, use different variable name
srmMap = srmMap.astype('uint8') # or you can try other opencv supported type
# I suppose that srmMap is your image returned as numpy array
cv2.imwrite('name.jpeg', srmMap)
# or
cv2.imshow('image', srmMap)
cv2.waitKey(0)

python convert IplImage to Qimage

I am trying to process some videos using openCV and then put it inside pyqt Qimage...
I saw some examples to do that but they are all in C++ and I can understand python only,
Can anyone help me please ... thank you
You can use the following code to convert numpy arrays to QImage:
from PyQt4.QtGui import QImage, qRgb
import numpy as np
class NotImplementedException:
pass
gray_color_table = [qRgb(i, i, i) for i in range(256)]
def toQImage(im, copy=False):
if im is None:
return QImage()
if im.dtype == np.uint8:
if len(im.shape) == 2:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_Indexed8)
qim.setColorTable(gray_color_table)
return qim.copy() if copy else qim
elif len(im.shape) == 3:
if im.shape[2] == 3:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_RGB888);
return qim.copy() if copy else qim
elif im.shape[2] == 4:
qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_ARGB32);
return qim.copy() if copy else qim
raise NotImplementedException
and then just convert OpenCV's CvMat to a numpy array before calling toQImage()
arr = numpy.asarray(mat)
qim = toQImage(arr)
See also http://opencv.willowgarage.com/documentation/python/cookbook.html for the conversion between OpenCV's CvMat and numpy arrays.
This worked for me.
camcapture = cv.CaptureFromCAM(0)
cv.SetCaptureProperty(camcapture,cv.CV_CAP_PROP_FRAME_WIDTH, 1280)
cv.SetCaptureProperty(camcapture,cv.CV_CAP_PROP_FRAME_HEIGHT, 720);
frame = cv.QueryFrame(camcapture)
image = QImage(frame.tostring(), frame.width, frame.height, QImage.Format_RGB888).rgbSwapped()
pixmap = QPixmap.fromImage(image)
I wanted to ask the same question from cvMat to QImage conversation and I didn't find any example for python.
I solved it like this:
pano = cv.CreateMat(int(height),int(width),0)
cv.Zero(pano)
cv.Resize(self.image,pano)
self._data=pano.tostring('raw')
image2=QImage(self._data,pano.width,pano.height,QtGui.QImage.Format_Indexed8)
self.imageLabel.setPixmap(QPixmap(image2))
This function worked for me using QT5, using a JPEG from local disk
from PyQt5.QtGui import QImage
def convertMatToQImage(cvImg):
return QImage(cvImg.data, cvImg.shape[1], cvImg.shape[0], QImage.Format_RGB32)

Categories

Resources