【问题描述】
【C++解决】
我都不知道该如何准确去描述这个问题。就是我从摄像头获取实时数据绘图,但是显示图像的窗口毕竟有固定的大小。
在未操作之前,再一定的时间后,从摄像头中获取数据画的线段就会超出窗口界面,因此其实后面画的实时图像我是没法获取到的。
能够显示的永远只有窗口开始的这一段。
void Draw_now(double EAR) {
Count(EAR);//顺便计算一下cnt
eye_now_x = eye_now_x + 1; //横坐标(每10个像素描一个点)
eye_now_y = 400*(1-EAR/0.4); //纵坐标
Point pos1 = Point(eye_pre_x, eye_pre_y);//上一个点
Point pos2 = Point(eye_now_x, eye_now_y);//现在的点
cv::line(Eye_Waveform, pos1, pos2, Scalar(0, 0, 0), 1, LINE_AA);//画线-黑色
eye_pre_x = eye_now_x;
eye_pre_y = eye_now_y;
}
\\ \\ \\ \\ \\ \\
【解决方案1】
针对图像做更新轨迹:有以下方法。
每到界面的边界就进行更新:重新刷新界面(init)。对于该想法需要查阅是否存在可以一键清除所有画的线一键清除。
由于我设置的窗口的大小是420*420.
进行了一点改进,显然不太可。
void Draw_now(double EAR) {
Count(EAR);//顺便计算一下cnt
eye_now_x = eye_now_x + 1; //横坐标(每10个像素描一个点)
if (eye_now_x == 420) { //----------------添加
Draw_init(); // |
eye_pre_x = 20; // |
eye_pre_y = 400; // |
eye_now_x = 20; // |
} //----------------添加
eye_now_y = 400*(1-EAR/0.4); //纵坐标
Point pos1 = Point(eye_pre_x, eye_pre_y);//上一个点
Point pos2 = Point(eye_now_x, eye_now_y);//现在的点
cv::line(Eye_Waveform, pos1, pos2, Scalar(0, 0, 0), 1, LINE_AA);//画线-黑色
eye_pre_x = eye_now_x;
}
\\\\
得到的结果:
没有对原有的画线进行删除,使得第一次的线和第二次的线缠在一起了。
我以为Draw_init()
能成功,但是显然失败了。
if (eye_now_x == 420) {
destroyWindow("Blink waveform figure");//会抛出异常异常
imshow("Blink waveform figure", Eye_Waveform);
Draw_init();
eye_pre_x = 20;
eye_pre_y = 400;
eye_now_x = 20;
}
又寄了,看来并没有我想象的那么容易。
重新换个角度来思考,就是:我的waveform图像是由Mat Eye_Waveform
数组来显示的。但是我不断的画线相当于改变了原有的图像的性质。也就是Mat Eye_Waveform
上面已经存在这些线了。既然如此,我属实没有办法让一切回到最初的样子,只能选择删除原有的Mat。
\\\\
于是我重新翻了翻工具书,找一下Mat这章。果然找到了那么一个函数,它叫clone(),做的就是覆盖数组的功能。于是果然就成功了。
void Draw_now(double EAR) {
Count(EAR);//顺便计算一下cnt
if(cnt)eye_now_x = eye_now_x + 1; //横坐标(每10个像素描一个点)
if (eye_now_x == 421) {
Eye_Waveform = Waveform_Copy.clone(); //更换为clone()函数来拷贝初始图像的副本即可
eye_pre_x = 20;
eye_now_x = 21;
}
eye_now_y = 400*(1-EAR/0.4); //纵坐标
Point pos1 = Point(eye_pre_x, eye_pre_y);//上一个点
Point pos2 = Point(eye_now_x, eye_now_y);//现在的点
if(cnt)cv::line(Eye_Waveform, pos1, pos2, Scalar(0, 0, 0), 1, LINE_AA);//画线-黑色
eye_pre_x = eye_now_x;
eye_pre_y = eye_now_y;
cnt++;
}
\\\\
【解决方案2】超简单!!
我是感觉这个图才是我想要的那种结果,不过上面的方案1也能实现啦。
通过调用cvzone的一个包,貌似是集成了一些常用的OpenCV的许多的库内函数,终于让我找到了自动画图,同步更新的方法!嘎嘎)但是用的是Python来实现的,大家自己斟酌。
大概的用法如下:
from cvzone.PlotModule import LivePlot
plot = LivePlot(640, 360, [10, 45], invert=True)# 画动态图像的
imgPlot = plot.update(ratioAvg, color)# 这里的颜色可以改变的喔
然后是效果图:
再放一下PlotMoudule的源码辣:
import cv2
import numpy as np
import time
import math
class LivePlot:
def __init__(self, w=640, h=480, yLimit=[0, 100],
interval=0.001, invert=False, char=' '):
self.yLimit = yLimit
self.w = w
self.h = h
self.invert = invert
self.interval = interval
self.char = char[0]
self.imgPlot = np.zeros((self.h, self.w, 3), np.uint8)
self.imgPlot[:] = 225, 225, 225
cv2.rectangle(self.imgPlot, (0, 0),
(self.w, self.h),
(0, 0, 0), cv2.FILLED)
self.xP = 0
self.yP = 0
self.yList = []
self.xList = [x for x in range(0, 100)]
self.ptime = 0
def update(self, y, color=(255, 0, 255)):
if time.time() - self.ptime > self.interval:
# Refresh
self.imgPlot[:] = 225, 225, 225
# Draw Static Parts
self.drawBackground()
# Draw the text value
cv2.putText(self.imgPlot, str(y),
(self.w - (125), 50), cv2.FONT_HERSHEY_PLAIN,
3, (150, 150, 150), 3)
if self.invert:
self.yP = int(np.interp(y, self.yLimit,
[self.h, 0]))
else:
self.yP = int(np.interp(y, self.yLimit,
[0, self.h]))
self.yList.append(self.yP)
if len(self.yList) == 100:
self.yList.pop(0)
for i in range(0, len(self.yList)):
if i < 2:
pass
else:
cv2.line(self.imgPlot, (int((self.xList[i - 1] * (self.w // 100))) - (self.w // 10),
self.yList[i - 1]),
(int((self.xList[i] * (self.w // 100)) - (self.w // 10)),
self.yList[i]), color, 2)
self.ptime = time.time()
return self.imgPlot
def drawBackground(self):
# Draw Background Canvas
cv2.rectangle(self.imgPlot, (0, 0),
(self.w, self.h),
(0, 0, 0), cv2.FILLED)
# Center Line
cv2.line(self.imgPlot, (0, self.h // 2), (self.w, self.h // 2), (150, 150, 150), 2)
# Draw Grid Lines
for x in range(0, self.w, 50):
cv2.line(self.imgPlot, (x, 0), (x, self.h),
(50, 50, 50), 1)
for y in range(0, self.h, 50):
cv2.line(self.imgPlot, (0, y), (self.w, y),
(50, 50, 50), 1)
# Y Label
cv2.putText(self.imgPlot,
f'{int(self.yLimit[1] - ((y / 50) * ((self.yLimit[1] - self.yLimit[0]) / (self.h / 50))))}',
(10, y), cv2.FONT_HERSHEY_PLAIN,
1, (150, 150, 150), 1)
cv2.putText(self.imgPlot, self.char,
(self.w - 100, self.h - 25), cv2.FONT_HERSHEY_PLAIN,
5, (150, 150, 150), 5)
def main():
xPlot = LivePlot(w=1200, yLimit=[-100, 100], interval=0.01)
x = 0
while True:
x += 1
if x == 360: x = 0
imgPlot = xPlot.update(int(math.sin(math.radians(x)) * 100))
cv2.imshow("Image", imgPlot)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if __name__ == "__main__":
main()