opencv实现魔幻笔效果

简介

  在使用美图秀秀之类工具的时候,发现了一个魔幻笔效果,然后这里用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);
	    }
	}
   }

效果演示

  对应的效果演示如下:
                                  
时间: 2024-12-25 13:09:08

opencv实现魔幻笔效果的相关文章

OpenCV——PS滤镜 水波效果

// define head function #ifndef PS_ALGORITHM_H_INCLUDED #define PS_ALGORITHM_H_INCLUDED #include <iostream> #include <string> #include "cv.h" #include "highgui.h" #include "cxmat.hpp" #include "cxcore.hpp&quo

图像边缘检测--OpenCV之cvCanny函数

图像边缘检测--OpenCV之cvCanny函数 分类: C/C++ void cvCanny( const CvArr* image, CvArr* edges, double threshold1, double threshold2, int aperture_size=3 ); image单通道输入图像.edges单通道存储边缘的输出图像threshold1第一个阈值threshold2第二个阈值aperture_sizeSobel 算子内核大小 (见 cvSobel). 函数 cvCa

opencv实现拼图功能

简介 在使用美图秀秀之类工具的时候,发现了一个拼图功能,然后这里用opencv实现了类似效果. 实现原理 具体代码 #include <math.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <

sobel算子实现边缘检测及其c++实现及与matlab效果对比

这里增加了对边缘像素的补齐.sobel梯度分割抗噪性好,但是无法做到自动阈值,是其一大遗憾,matlab却解决的很好. //默认对8位位图进行处理 void Sobel(unsigned char *pIn, int width, int height, unsigned char *pOut) { //每行像素所占字节数,输出图像与输入图像相同 int lineByte=(width+3)/4*4; //申请输出图像缓冲区 pOut=new unsigned char[lineByte*hei

斑点检测

1. 什么是斑点 斑点通常是指与周围有着颜色和灰度差别的区域.在实际地图中,往往存在着大量这样的斑点,如一颗树是一个斑点,一块草地是一个斑点,一栋房子也可以是一个斑点.由于斑点代表的是一个区域,相比单纯的角点,它的稳定性要好,抗噪声能力要强,所以它在图像配准上扮演了很重要的角色. 同时有时图像中的斑点也是我们关心的区域,比如在医学与生物领域,我们需要从一些X光照片或细胞显微照片中提取一些具有特殊意义的斑点的位置或数量. 比如下图中天空的飞机.向日葵的花盘.X线断层图像中的两个斑点.      在

图像特征提取:斑点检测

1. 什么是斑点 斑点通常是指与周围有着颜色和灰度差别的区域.在实际地图中,往往存在着大量这样的斑点,如一颗树是一个斑点,一块草地是一个斑点,一栋房子也可以是一个斑点.由于斑点代表的是一个区域,相比单纯的角点,它的稳定性要好,抗噪声能力要强,所以它在图像配准上扮演了很重要的角色. 同时有时图像中的斑点也是我们关心的区域,比如在医学与生物领域,我们需要从一些X光照片或细胞显微照片中提取一些具有特殊意义的斑点的位置或数量. 比如下图中天空的飞机.向日葵的花盘.X线断层图像中的两个斑点.      在

Pok&#233;mon GO国内玩不了?腾讯AR专家教你自己做!

作者:Zero,腾讯测试开发工程师 本文由腾讯WeTest授权发布,如需转载请联系腾讯WeTest获得授权. WeTest导读 Pokémon Go一出,新鲜的玩法.经典的IP效应让这款使用了Unity以及AR技术的手游火遍了"大洋"南北.可惜的是这款新鲜的游戏还没有惠及中国市场的玩家们.腾讯内部的AR专家秉持着"一言不合就自己开发"的原则,自发对AR游戏进行了预研,本文将通过在Unity中对OpenCV及Vuforia库的使用,简单介绍制作AR游戏的一系列流程.

opencv中值滤波和低通滤波器对椒盐噪声处理的效果比较

opencv中值滤波和低通滤波器对椒盐噪声处理的效果比较 效果: 通过比较我们可以看出,中值滤波器有很好的保留了图像的边界信息 代码: void showimage(const std::string &str,const cv::Mat &image){ namedWindow(str,CV_WINDOW_AUTOSIZE); imshow(str,image); } Mat salt(const cv::Mat &image,int n){ Mat result = image

OpenCV 实现哈哈镜效果

代码,有参考别人的代码 // haha_mirror.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include "cv.h" #include "highgui.h" #include "math.h" #include "opencv2/core/core.hpp" #pragma comment(lib,&