英文:
How to crop a live video feed in PyQt5? QImage looks sheared
问题
我有一个PyQt5 GUI应用程序。我从摄像头读取一帧来选择其中的一个较小区域,稍后我想只显示该区域。我正确地选择了这个区域,并将其存储在一个QRect中。但当我尝试裁剪帧以显示和稍后处理时,显示的实时视频有时候能正确工作,但大多数时候看起来像图片上这样。它变得倾斜,右上角应该是左上角。粉色的圆应该在视频的中间,所以有点不对劲。
英文:
I have a PyQt5 GUI application. I read a frame from the camera to select a smaller area on it, and later I would like to display only that area. I correctly select the area, and store it in a QRect. But when I try to crop the frames to display and to process later, the displayed live video just sometimes works correctly. but most of the times it looks like on this picture. It becomes slanted, the right corner should be the left corner. And the pink circle should be in the middle of the video, so it is kinda wrong.
I have this Worker1 class, where I process the displayed frames.
class Worker1(QThread):
ImageUpdate = pyqtSignal(QImage)
def __init__(self, canvas, selection):
super().__init__()
self.ThreadActive = True
self.canvas = canvas
self.anim = None
self.selection = selection
def run(self):
Capture = cv.VideoCapture(0)
old_closest_contour = None
d_tresh = 300
P_color = (0, 255, 0)
global i
i = 0
while self.ThreadActive:
i += 1
ret, frame = Capture.read()
if ret:
if self.selection is None or self.selection.isEmpty():
cropped_frame = frame
else:
a = int(self.selection.x())
b = int(self.selection.y())
width = int(self.selection.width())
height = int(self.selection.height())
#print(str(a) + " " + str(b) + " " + str(width) + " " + str(height))
cropped_frame = frame[b: b + height, a: a + width].copy()
#print(cropped_frame.shape[1])
#print(cropped_frame.shape[0])
### other processing lines, those are not relevant in the displaying ###
Image = cv.cvtColor(cropped_frame, cv.COLOR_BGR2RGB)
img = cv.medianBlur(Image, 25)
cv.circle(img, (x, y), r, P_color, 1)
cv.circle(img, (x, y), 4, P_color, -1)
cv.circle(img, point, 0, (255, 0, 255), 10)
ConvertToQtFormat = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_RGB888)
self.ImageUpdate.emit(ConvertToQtFormat)
Capture.release()
答案1
得分: 0
We have to set bytesPerLine
argument.
Replace ConvertToQtFormat = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_RGB888)
with:
ConvertToQtFormat = QImage(img.data, img.shape[1], img.shape[0], img.strides[0], QImage.Format_RGB888)
img.strides[0]
应用于 img
中每行的字节数。
当 img.shape[1] = 100
时,通常情况下,img.strides[0]
等于 100*3
= 300
字节,当每个像素有3个字节时。
之所以有 strides
是因为存在内存中行不连续的情况,而步长不等于宽度 * 3。
QImage
对象中的等效参数是 bytesPerLine
。
默认情况下,QImage
对象假定 bytesPerLine
是4的倍数。
如果宽度*3不是4的倍数,则假定每行末尾存在填充字节。
例如,当宽度 = 101 时,bytesPerLine
为304,而不是303(假定有1个填充字节)。
(4的倍数假设来源于BMP图像格式)。
在我们的情况下:
- 当
img.shape[1]
是4的倍数时,图像将看起来正确。 - 当
img.shape[1]
不是4的倍数时,图像将会 "倾斜"。
在我们的情况下,NumPy数组没有填充字节,Qt的bytesPerLine
和NumPy的strides
之间存在不匹配。
解决方法是设置bytesPerLine
参数(使用重载的QImage
构造函数)。
通常情况下,从NumPy转换为QImage时,我们应该将img.strides[0]
设置为bytesPerLine
参数。
英文:
We have to set bytesPerLine
argument.
Replace ConvertToQtFormat = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_RGB888)
with:
ConvertToQtFormat = QImage(img.data, img.shape[1], img.shape[0], img.strides[0], QImage.Format_RGB888)
img.strides[0]
applies the number of bytes in each line of img
.
When img.shape[1] = 100
, img.strides[0]
is usually equal 100*3
= 300
bytes when there are 3 bytes per pixel.
The reason that we have the strides
is that there are cases when lines are not continuous in memory, and the stride doesn't equal width * 3.
The equivalent parameter in QImage
object is bytesPerLine
.
By default, QImage object assumes that bytesPerLine
is a multiple of 4.
In case width*3 is not a multiple of 4, padding bytes are assumed to be present at the end of each line.
For example, when width = 101, bytesPerLine
is 304 instead of 303 (1 padding byte is assumed).
(The multiple of 4 assumption is originated from the BMP image format).
In our case:
- When
img.shape[1]
is a multiple of 4, the image is going to look correct. - When
img.shape[1]
is a not multiple of 4, the image is going to be "slanted".
In our case the NumPy array has no padding bytes, and there is a mismatch between QtbytesPerLine
and NumPystrides
.
The solution is setting the bytesPerLine
parameter (using an overloaded QImage
constructor).
In general, when converting from NumPy to QImage, we should set img.strides[0]
as bytesPerLine
argument.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论