opencv实现魔幻笔效果
来源:互联网 发布:openwrt搭建php 编辑:程序博客网 时间:2024/06/09 20:33
简介
在使用美图秀秀之类工具的时候,发现了一个魔幻笔效果,然后这里用opencv实现了类似效果。
实现原理
具体实现
表现效果是,当鼠标左键在图片窗口上按下时候,会从鼠标当前坐标位置,不断的出现小方框向四面八方散去。使用的基本原理,就是前面讲过的图像比例混合。两种图片,一张是背景图片,另外一种是各色小方框图片。当鼠标按下时候,小方框图片源源不断的生成,然后和背景图片比例混合后,以随机的速度,发散出去。
实现代码
#include <math.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv/cv.h>#include "lib/normal.h"#include <math.h> using namespace cv; #define RECT_NUMBER 16 Mat src, src2, imageROI;int width=0, height=0;int src2_width, src2_height;int mouse_width, mouse_height;double alpha = 0.3, beta;char pic_name[20];bool mouse_left = false; int curRectAddr[RECT_NUMBER][5];Scalar scalar[RECT_NUMBER];int rect_num = 2;RNG rng(0xFFFFFFFF); void on_mouse( int event, int x, int y, int flags, void* ustc){int i; if(event == CV_EVENT_LBUTTONDOWN){mouse_left = true;}else if(event == CV_EVENT_LBUTTONUP){mouse_left = false;}if(mouse_left){rect_num ++;if(rect_num >= 2){for(i=0; i<RECT_NUMBER; i++){if(curRectAddr[i][4] == 0){curRectAddr[i][0] = x; /*rect(i)的初始width*/curRectAddr[i][1] = y; /*rect(i)的初始height*/curRectAddr[i][2] = rng.uniform(-20, 20); /*rect(i)的width偏移速度*/curRectAddr[i][3] = rng.uniform(-20, 20); /*rect(i)的height偏移速度*/if((curRectAddr[i][2] == 0) && (curRectAddr[i][3] == 0)){curRectAddr[i][2] = 10;curRectAddr[i][3] = 10;}curRectAddr[i][4] = 1; /*rect(i)的存在状态*/rect_num = 0;scalar[i][0] = rng.uniform(0, 255);scalar[i][1] = rng.uniform(0, 255);scalar[i][2] = rng.uniform(0, 255);break;}}}}} void add_rect(Mat mat, int num){curRectAddr[num][0] = curRectAddr[num][0] - curRectAddr[num][2];curRectAddr[num][1] = curRectAddr[num][1] - curRectAddr[num][3];if((curRectAddr[num][0] < 0) || (curRectAddr[num][1] < 0)){curRectAddr[num][4] = 0;return;}if(curRectAddr[num][0] > (width - src2_height)){curRectAddr[num][4] = 0;return;}if(curRectAddr[num][1] > (height - src2_width)){curRectAddr[num][4] = 0;return;}imageROI = src(cv::Rect(curRectAddr[num][0], curRectAddr[num][1], src2_height, src2_width));beta = 1 - alpha;addWeighted(imageROI, alpha, src2, beta, 0.0, imageROI);} int main(int agrc, char* argv[]){char c;int i; memcpy(pic_name,argv[1],sizeof(argv[1]));src=imread(pic_name,1);width = src.cols;height = src.rows;src2_width = width / 10;src2_height = height / 10;src2 = Mat(src2_width, src2_height, CV_8UC3, 1);IplImage img = src2;cvZero(&img);mouse_width = width/2;mouse_height = height/2; namedWindow("src", 1);cvSetMouseCallback("src", on_mouse, NULL);while(1){c = waitKey(20);if(c == 'q'){break;}if(mouse_left){src=imread(pic_name,1);for(i=0; i<RECT_NUMBER; i++){if(curRectAddr[i][4] != 0){rectangle(src2,cvPoint(0, 0), cvPoint(src2_height, src2_width), scalar[i], -1);add_rect(src, i);}}}imshow("src",src);}cvDestroyAllWindows(); return 0; }
代码讲解
1、首先是打开传入的背景图片src,获得它的相关信息。接着初始化小方块图片,设置它的大小,和将用cvZero进行初始化。
memcpy(pic_name,argv[1],sizeof(argv[1])); src=imread(pic_name,1);width = src.cols;height = src.rows;src2_width = width / 10;src2_height = height / 10;src2 = Mat(src2_width, src2_height, CV_8UC3, 1);IplImage img = src2;cvZero(&img);
2、接着进入一个死循环中,当鼠标没有按下的时候,除了键值等待之外,不做任何操作。注意如果按下键值'q',则会退出程序。
while(1){c = waitKey(20);if(c == 'q'){break; } .......... imshow("src",src); }
3、鼠标左键按下,mouse_left为true,则对方框进行初始化,rect_num作为方块产生的延时,同时一共设置了最多可以生成RECT_NUMBER 16个方块。方块参数保存在:curRectAddr和scalar中,假设以第一个方框为例:它的参数就保存在curRectAddr[0]和scalar[0]中。具体参数解释如下: curRectAddr[i][0] = x; /*rect(i)的初始width*/ curRectAddr[i][1] = y; /*rect(i)的初始height*/ curRectAddr[i][2] = rng.uniform(-20, 20); /*rect(i)的width偏移速度*/ curRectAddr[i][3] = rng.uniform(-20, 20); /*rect(i)的height偏移速度*/ curRectAddr[i][4] = 1; /*rect(i)的生存状态*/ scalar[0] /*方块的颜色*/ 注意,如果随机生成出来的方块width和height的便宜速度都为0的话,则强行设置它们的偏移速度都为10。 当鼠标左键抬起之后,mouse_left为false。停止生成小方块。
void on_mouse( int event, int x, int y, int flags, void* ustc){int i; if(event == CV_EVENT_LBUTTONDOWN){mouse_left = true;}else if(event == CV_EVENT_LBUTTONUP){mouse_left = false;}if(mouse_left){rect_num ++;if(rect_num >= 2){for(i=0; i<RECT_NUMBER; i++){if(curRectAddr[i][4] == 0){curRectAddr[i][0] = x; /*rect(i)的初始width*/curRectAddr[i][1] = y; /*rect(i)的初始height*/curRectAddr[i][2] = rng.uniform(-20, 20); /*rect(i)的width偏移速度*/curRectAddr[i][3] = rng.uniform(-20, 20); /*rect(i)的height偏移速度*/if((curRectAddr[i][2] == 0) && (curRectAddr[i][3] == 0)){curRectAddr[i][2] = 10;curRectAddr[i][3] = 10;}curRectAddr[i][4] = 1; /*rect(i)的存在状态*/rect_num = 0;scalar[i][0] = rng.uniform(0, 255);scalar[i][1] = rng.uniform(0, 255);scalar[i][2] = rng.uniform(0, 255);break;}}}}}
4、在main的循环中,由于鼠标左键按下,mouse_left为true。就会实时更新存在状态为1的小方块在背景图的位置。当小方块偏移出背景图之后。就会将该方块生存状态置为0.停止对它的刷新。
void add_rect(Mat mat, int num){curRectAddr[num][0] = curRectAddr[num][0] - curRectAddr[num][2];curRectAddr[num][1] = curRectAddr[num][1] - curRectAddr[num][3];if((curRectAddr[num][0] < 0) || (curRectAddr[num][1] < 0)){curRectAddr[num][4] = 0;return;}if(curRectAddr[num][0] > (width - src2_height)){curRectAddr[num][4] = 0;return;}if(curRectAddr[num][1] > (height - src2_width)){curRectAddr[num][4] = 0;return;}imageROI = src(cv::Rect(curRectAddr[num][0], curRectAddr[num][1], src2_height, src2_width));beta = 1 - alpha;addWeighted(imageROI, alpha, src2, beta, 0.0, imageROI);} if(mouse_left){src=imread(pic_name,1);for(i=0; i<RECT_NUMBER; i++){ if(curRectAddr[i][4] != 0){rectangle(src2,cvPoint(0, 0), cvPoint(src2_height, src2_width), scalar[i], -1);add_rect(src, i); }} }
效果演示
对应的效果演示如下:
0 0
- opencv实现魔幻笔效果
- OpenCV 实现哈哈镜效果
- openCV实现卡通画的效果
- opencv实现图像细化效果
- opencv实现图片动画效果
- 文字模糊效果(Opencv实现)
- 高斯平滑滤波器opencv实现效果
- 雕刻效果的实现【OpenCV+QT】
- OpenCV实现马赛克和毛玻璃滤镜效果
- 简单的 AR 效果实现【OpenGL】【OpenCV】
- OpenCV 在iOS平台实现马赛克效果
- OpenCV编写毛玻璃效果实现(需进一步提高)
- 《Mastering Opencv读书笔记》第一章 实现图像卡通效果
- opencv 实现图像倒影(渐变)效果【源码】
- openCV实现图片的时钟和中心圆形扩大效果
- 魔幻数字
- 魔幻计时器
- 魔幻数字
- [python] 密码学:希尔加密的实现
- Java可变参数学习
- 计数器排序
- 90后的奋斗宣言!
- KMP字符串匹配
- opencv实现魔幻笔效果
- HDU1234开门人和关门人
- 几十个小时没睡觉 没事干开开csdn的博客
- Gray Hat --Learning Python Chapter 1
- java配置环境
- java学习之路的自我回顾5(集合)
- 为什么在“非阻塞+io复用网络模型”中用户缓冲区管理变得复杂了?
- 在字符串中查找第一个只出现一次的字符
- 凯云水利水电造价工程系统 技术解析(一) MVC架构的搭建