OpenCV画出时钟并动态同步系统时间
opencv吧
全部回复
仅看楼主
level 6
zeus冰不语 楼主
先上效果图。
本文并非原创,是在外网上看到的一个实例。不是翻译,也不是转载,只是自己实现了下,一点小记录。代码略有改动。
过程大致分为两步:
第一步,画出时钟;
第二步,同步系统时间。
其中第一步是跟opencv相关,第二步不太了解,不作过多记录。
一个简单的时钟就是线段和圆的组合。包括最外围的圆,60根刻度线(其中12根整点刻度线)和时针分针秒针三根长的线段。
画圆最简单:创建一个长宽相等的图片,以图片中心为中心,以一半的图片长宽为半径画圆即可。
画线段就相对麻烦许多,因为一共要画60+12
+3
=75根线段。opencv的画线函数line()需要知道线段的起始点,而我们需要画的75根直线的起始点各不相同,我们需要一一计算出来。如果我们的圆是以我们数学上的笛卡尔坐标系的原点为中心,以r为半径画的圆,大概就是下面这样:
已知角度α的情况下我们可以很容易算到P点的坐标:
x = r * cos(α)
y = r * sin(α)
但是我们知道opencv中图像的坐标原点在左上角,那么我们可以变化下坐标系,得到下面的公式:
x = r + r * cos(α)
y = r + r * sin(α)
一分钟60秒,秒针刻度就是把外围的圆60等分,每两个刻度的夹角是6度。同理整点刻度就是把圆12等分,夹角为30度。
我们可以用半径相差不大的一大一小两个圆来算出每一根刻度线的起始点坐标,然后就可以用line()画出它们了。整点刻度同理。
画出刻度线之后获取系统时间,然后根据时间实时画出时针分针秒针。这一部分不太了解,就不多说了。代码如下:
#include <iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/imgproc/imgproc.hpp"
#include <stdio.h>
#include <time.h>
#include <sys/timeb.h>
//#include <sys/time.h>
#include<sys\utime.h>
using namespace std;
using namespace cv;
int main()
{
Mat clk(640, 640, CV_8UC3,Scalar(180,120,50)); //Mat to store clock image
Mat back_up(640, 640, CV_8UC3, Scalar(180, 120, 50)); //Mat to store backup image
Point cent(clk.rows/2, clk.cols/2);
Point perim(clk.cols/2, 0);
int rad = clk.cols / 2;
float sec_angle = 270;
float min_angle = 330;
float hour_angle = 210;
//画秒针刻度
vector<Point> pt1,pt2;
for (int i = 0; i < 60; i++)
{
int x1 = cent.x + rad*cos(i * 6 * CV_PI / 180.0);
int y1 = cent.y + rad*sin(i * 6 * CV_PI / 180.0);
pt1.push_back(Point(x1, y1));
int x2 = cent.x + (rad - 20)*cos(i * 6 * CV_PI / 180.0);
int y2 = cent.y + (rad - 20)*sin(i * 6 * CV_PI / 180.0);
pt2.push_back(Point(x2, y2));
line(clk, pt1[i], pt2[i], Scalar(0, 255, 0, 0), 1.5, CV_AA, 0);
}
vector<Point> pt3,pt4;
for (int i = 0; i < 12; i++)
{
int x3 = cent.x + (rad - 40)*cos(i * 30 * CV_PI / 180.0);
int y3 = cent.y + (rad - 40)*sin(i * 30 * CV_PI / 180.0);
pt3.push_back(Point(x3, y3));
line(clk, pt1[(i*5)], pt3[i], Scalar(0, 255, 0, 0), 5, CV_AA, 0);
}
//画最外围的圆和圆心的三针连接点
circle(clk, cent, rad, Scalar(50, 50, 255, 0), 6, CV_AA, 0); //Dreaw outercircle of clock
circle(clk, cent, 2, Scalar(0, 255, 0, 0), 5, CV_AA, 0); //Draw inner circle
back_up = clk.clone(); // Clone to backup image
time_t rawtime;
struct tm * timeinfo;
float second;
float minute;
float hour;
float millisec;
struct timeb tmb;
while (1){
//获取本地时间
ftime(&tmb);
rawtime = tmb.time;
timeinfo = localtime (&rawtime);
second = timeinfo->tm_sec;
minute = timeinfo->tm_min;
hour = timeinfo->tm_hour;
millisec = tmb.millitm;
second = second + millisec / 1000;
sec_angle = (second * 6) + 270; //Convert second to angle
minute = minute + second / 60;
min_angle = minute * 6 + 270; //Conver minute to angle
if (hour>12)hour = hour - 12;
hour_angle = (hour * 30) + (minute*.5) + 270; //Conver hour to angle
if (sec_angle>360)sec_angle = sec_angle - 360;
if (min_angle>360)min_angle = min_angle - 360;
if (hour_angle>360)hour_angle = hour_angle - 360;
//画秒针
perim.x = (int)round(cent.x + (rad - 5) * cos(sec_angle * CV_PI / 180.0));
perim.y = (int)round(cent.y + (rad - 5) * sin(sec_angle * CV_PI / 180.0));
line(clk, cent, perim, Scalar(0, 255, 255, 0), 1.5, CV_AA, 0);
//画分针
perim.x = (int)round(cent.x + (rad - 30) * cos(min_angle * CV_PI / 180.0));
perim.y = (int)round(cent.y + (rad - 30) * sin(min_angle * CV_PI / 180.0));
line(clk, cent, perim, Scalar(0, 255, 255, 0), 4, CV_AA, 0);
//画时针
perim.x = (int)round(cent.x + (rad - 100) * cos(hour_angle * CV_PI / 180.0));
perim.y = (int)round(cent.y + (rad - 100) * sin(hour_angle * CV_PI / 180.0));
line(clk, cent, perim, Scalar(0, 255, 255, 0), 12, CV_AA, 0);
imshow("Clock", clk); //Show result in a window
clk.setTo(0); // set clk image to zero for next drawing
clk = back_up.clone(); // Clone the previously drawned markings from back-up image
char c = waitKey(999); // 这里如果参数为10,则看到的是秒针连续地转动;如果是1000,则效果是秒针一秒一秒地跳动
if (c == 27)break;
}
return 0;
}
对于自己的学习记录主要记录在http://blog.csdn.net/xingchenbingbuyu
请大家多多指点,大家多多交流。
2016年03月03日 11点03分 1
level 6
zeus冰不语 楼主
2016年03月03日 11点03分 2
@go一米阳光asd [太开心]多谢多谢
2016年03月07日 01点03分
level 6
zeus冰不语 楼主
2016年03月03日 11点03分 3
level 6
zeus冰不语 楼主
图都是动态图,需要打开才能看到动。。。
2016年03月03日 11点03分 4
level 4
厉害👍🏻
2016年04月25日 11点04分 5
参考的别人的代码,还在学习中
2016年04月25日 13点04分
level 4
楼请教下我用你的程序在VS2015上运行显示这块要改一下
while (1){
//获取本地时间
ftime(&tmb);
rawtime = tmb.time;
timeinfo = localtime (&rawtime);
报错,提示localtime unsafe,要换成localtime_s这个函数,但是这个有两个变量,要怎么添加呢?localtime_s(tm *_Tm,const time_t *_time)
求解答
2016年06月11日 13点06分 6
抱歉这个我也不知道,我的vs2013没有这个问题。你还是百度或者谷歌一下吧
2016年06月11日 14点06分
在项目属性里面设置一下,这是而已忽略的问题http://jingyan.baidu.com/article/49711c616b8a1ffa441b7cdc.html
2016年08月04日 05点08分
level 4
不错,值得学习,顶一个
2016年06月17日 09点06分 9
level 7
为什么代码总显示round是未定义的标识符啊。。。心好痛
2016年06月22日 08点06分 10
头文件正确的话。。。有可能是标点的错误
2016年06月22日 10点06分
回复 zeus冰不语 :会不会因为我用的是2010,有些语法不兼容
2016年06月22日 15点06分
round改成cvRound就可以了
2016年07月29日 06点07分
level 4
大神我看了你的博客就是那个最新的识别自己的脸,里面有些程序运行结果不对……我能加你qq什么的问问你吗[泪][泪]
2016年06月23日 08点06分 11
并不是大神。不过可以交流一下,私信我你的联系方式
2016年06月23日 08点06分
@zeus冰不语 楼主我加你了,通过下呀
2016年06月23日 11点06分
level 8
对你的代码改了一下,用windowAPI获取时间,不会出现6楼的问题了。
2016年07月28日 10点07分 12
level 8
#include <iostream>
#include "opencv2/opencv.hpp"
#include <windows.h>
using namespace std;
using namespace cv;
int main()
{
Mat clk(450, 450, CV_8UC3, Scalar(180, 120, 50)); //Mat to store clock image
Mat back_up(450, 450, CV_8UC3, Scalar(180, 120, 50)); //Mat to store backup image
Point cent(clk.rows / 2, clk.cols / 2);
Point perim(clk.cols / 2, 0);
int rad = clk.cols / 2;
float sec_angle = 270;
float min_angle = 330;
float hour_angle = 210;
//画秒针刻度
vector<Point> pt1, pt2;
for (int i = 0; i < 60; i++)
{
int x1 = cent.x + rad*cos(i * 6 * CV_PI / 180.0);
int y1 = cent.y + rad*sin(i * 6 * CV_PI / 180.0);
pt1.push_back(Point(x1, y1));
int x2 = cent.x + (rad - 20)*cos(i * 6 * CV_PI / 180.0);
int y2 = cent.y + (rad - 20)*sin(i * 6 * CV_PI / 180.0);
pt2.push_back(Point(x2, y2));
line(clk, pt1[i], pt2[i], Scalar(0, rand() % 255, 0, 0), 1.5, CV_AA, 0);
}
vector<Point> pt3, pt4;
for (int i = 0; i < 12; i++)
{
int x3 = cent.x + (rad - 40)*cos(i * 30 * CV_PI / 180.0);
int y3 = cent.y + (rad - 40)*sin(i * 30 * CV_PI / 180.0);
pt3.push_back(Point(x3, y3));
line(clk, pt1[(i * 5)], pt3[i], Scalar(0, rand() % 255, 0, 0), 5, CV_AA, 0);
}
//画最外围的圆和圆心的三针连接点
circle(clk, cent, rad, Scalar(50, 50, rand() % 255, 0), 6, CV_AA, 0); //Dreaw outercircle of clock
circle(clk, cent, 2, Scalar(0, rand() % 255, 0, 0), 5, CV_AA, 0); //Draw inner circle
back_up = clk.clone(); // Clone to backup image
float second;
float minute;
float hour;
float millisec;
SYSTEMTIME sys;
ostringstream ostringstream_test;
while (1) {
//获取本地时间
GetLocalTime(&sys);
second = sys.wSecond;
minute = sys.wMinute;
hour = sys.wHour;
millisec = sys.wMilliseconds;
//输入当前时间到屏幕
ostringstream_test << hour << ":" << minute << ":" << second << ":" << millisec;
//在图片上输出文字
putText(clk, ostringstream_test.str(), Point2f(300,200), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255));
//清理一下ostringstream的空间
ostringstream_test.str("");
second = second + millisec / 1000;
sec_angle = (second * 6) + 270; //Convert second to angle
minute = minute + second / 60;
min_angle = minute * 6 + 270; //Conver minute to angle
if (hour>12)hour = hour - 12;
hour_angle = (hour * 30) + (minute*.5) + 270; //Conver hour to angle
if (sec_angle>360)sec_angle = sec_angle - 360;
if (min_angle>360)min_angle = min_angle - 360;
if (hour_angle>360)hour_angle = hour_angle - 360;
//画秒针
perim.x = (int)round(cent.x + (rad - 5) * cos(sec_angle * CV_PI / 180.0));
perim.y = (int)round(cent.y + (rad - 5) * sin(sec_angle * CV_PI / 180.0));
//line(clk, cent, perim, Scalar(0, 255, rand() % 255, 0), 1.5, CV_AA, 0);//闪光特效cool
line(clk, cent, perim, Scalar(0,0, 0, 0), 1.5, CV_AA, 0);
//画分针
perim.x = (int)round(cent.x + (rad - 30) * cos(min_angle * CV_PI / 180.0));
perim.y = (int)round(cent.y + (rad - 30) * sin(min_angle * CV_PI / 180.0));
line(clk, cent, perim, Scalar(0, 150, 150, 0), 4, CV_AA, 0);
//画时针
perim.x = (int)round(cent.x + (rad - 100) * cos(hour_angle * CV_PI / 180.0));
perim.y = (int)round(cent.y + (rad - 100) * sin(hour_angle * CV_PI / 180.0));
line(clk, cent, perim, Scalar(0, 200, 200, 0), 12, CV_AA, 0);
imshow("Clock", clk); //Show result in a window
clk.setTo(0); // set clk image to zero for next drawing
clk = back_up.clone(); // Clone the previously drawned markings from back-up image
char c = waitKey(10); // 这里如果参数为10,则看到的是秒针连续地转动;如果是1000,则效果是秒针一秒一秒地跳动
if (c == 27)break;
}
return 0;
}
2016年07月28日 10点07分 13
1