OpenCV-如何刷新动态图像

【问题描述】

【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()
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值