博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【opencv实战】哈哈镜
阅读量:4074 次
发布时间:2019-05-25

本文共 8714 字,大约阅读时间需要 29 分钟。

目录


因为要做一个项目,为了实现他的趣味性,所以想应用图像处理做一些东西,在上次完成卡通化之后,又了解了哈哈镜效果,想自己实现,从网上找了好多教程,都是以前的opencv版本的代码,在opencv3.0及以上版本已经不支持使用了。

可能最新学习opencv的小伙伴不了解什么是“以前的opencv版本”。所以我先简单介绍一下。

一、opencv的前身后世

1、简介

OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

OpenCV用C++语言编写,它的主要接口也是C++语言,但是依然保留了大量的C语言接口。所有新的开发和算法都是用C++接口。一个使用CUDA的GPU接口也于2010年9月开始实现。

其他的一些介绍就在这里不多说了,大家在网上也能找到。我主要再说一下在前面我说到的以前的opencv版本和新版本的差别。这个差别不是opencv2.0,opencv2.3.4,opencv3.0.0,opencv3.1.0,opencv3.4.0等等这些版本之间的差别。大家会发现,大家现在在学习opencv时,建立图像,用的时C++语言中的Mat类,最初的opencv是用C语言编写的,C语言是没有类的,那用C语言用的自然就是结构体。所以接下来我讲一下opencv结构体的表示。

2、IplImage介绍

在OpenCV中IplImage是表示一个图像的结构体,也是从OpenCV1.0到目前最为重要的一个结构;在之前的图像表示用IplImage,而且之前的OpenCV是用C语言编写的,提供的接口也是C语言接口;

英文注释版结构体如下:

typedef struct _IplImage{    int  nSize;             /* sizeof(IplImage) */    int  ID;                /* version (=0)*/    int  nChannels;         /* Most of OpenCV functions support 1,2,3 or 4 channels */    int  alphaChannel;      /* Ignored by OpenCV */    int  depth;             /* Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S,                               IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported.  */    char colorModel[4];     /* Ignored by OpenCV */    char channelSeq[4];     /* ditto */    int  dataOrder;         /* 0 - interleaved color channels, 1 - separate color channels.                               cvCreateImage can only create interleaved images */    int  origin;            /* 0 - top-left origin,                               1 - bottom-left origin (Windows bitmaps style).  */    int  align;             /* Alignment of image rows (4 or 8).                               OpenCV ignores it and uses widthStep instead.    */    int  width;             /* Image width in pixels.                           */    int  height;            /* Image height in pixels.                          */    struct _IplROI *roi;    /* Image ROI. If NULL, the whole image is selected. */    struct _IplImage *maskROI;      /* Must be NULL. */    void  *imageId;                 /* "           " */    struct _IplTileInfo *tileInfo;  /* "           " */    int  imageSize;         /* Image data size in bytes                               (==image->height*image->widthStep                               in case of interleaved data)*/    char *imageData;        /* Pointer to aligned image data.         */    int  widthStep;         /* Size of aligned image row in bytes.    */    int  BorderMode[4];     /* Ignored by OpenCV.                     */    int  BorderConst[4];    /* Ditto.                                 */    char *imageDataOrigin;  /* Pointer to very origin of image data                               (not necessarily aligned) -                               needed for correct deallocation */}IplImage;

中文注释版结构体如下:

typedef struct _IplImage    {        int  nSize;         /* IplImage大小 */        int  ID;            /* 版本 (=0)*/        int  nChannels;     /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */        int  alphaChannel;  /* 被OpenCV忽略 */        int  depth;         /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,                               IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */        char colorModel[4]; /* 被OpenCV忽略 */        char channelSeq[4]; /* 同上 */        int  dataOrder;     /* 0 - 交叉存取颜色通道, 1 - 分开的颜色通道.                               cvCreateImage只能创建交叉存取图像 */        int  origin;        /* 0 - 顶—左结构,                               1 - 底—左结构 (Windows bitmaps 风格) */        int  align;         /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */        int  width;         /* 图像宽像素数 */        int  height;        /* 图像高像素数*/        struct _IplROI *roi;/* 图像感兴趣区域. 当该值非空只对该区域进行处理 */        struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */        void  *imageId;     /* 同上*/        struct _IplTileInfo *tileInfo; /*同上*/        int  imageSize;     /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/        char *imageData;  /* 指向排列的图像数据 */        int  widthStep;   /* 排列的图像行大小,以字节为单位 */        int  BorderMode[4]; /* 边际结束模式, 被OpenCV忽略 */        int  BorderConst[4]; /* 同上 */        char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */    }    IplImage;

IplImage结构体是整个OpenCV函数库的基础,在定义该结构变量时需要用到函数cvCreatImage,变量定义方法如下:

//定义一个IplImage指针变量src,图像的大小是200×300,图像颜色深度8位,3通道图像。IplImage* src = "/cvCreateImage"(cvSize(200, 300), IPL_DEPTH_8U, 3);//定义一个IplImage指针变量src,图像的大小是200×300,图像颜色深度8位,单通道图像。IplImage* src = "/cvCreateImage"(cvSize(200, 300), IPL_DEPTH_8U, 1);

由于定义的src是一个指针变量,所以通过src来调用函数时,采用的是指向的方式:

//下面是两种图像数据存取方式的例子://1.直接存取 : (效率高, 但容易出错)//  对单通道字节图像 :IplImage* src = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 1);((uchar *)(src->imageData + i*src->widthStep))[j] = 111;//  对多通道字节图像:IplImage* src = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 3);((uchar *)(src->imageData + i*src->widthStep))[j*src->nChannels + 0] = 111; // B((uchar *)(src->imageData + i*src->widthStep))[j*src->nChannels + 1] = 112; // G((uchar *)(src->imageData + i*src->widthStep))[j*src->nChannels + 2] = 113; // R									 //  对多通道浮点图像:IplImage* src = cvCreateImage(cvSize(640, 480), IPL_DEPTH_32F, 3);((float *)(src->imageData + i*src->widthStep))[j*src->nChannels + 0] = 111; // B((float *)(src->imageData + i*src->widthStep))[j*src->nChannels + 1] = 112; // G((float *)(src->imageData + i*src->widthStep))[j*src->nChannels + 2] = 113; // R										//2.用指针直接存取 : (在某些情况下简单高效)	//  对单通道字节图像 :IplImage* src = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 1);int height = src->height;int width = src->width;int step = src->widthStep / sizeof(uchar);uchar* data = (uchar *)src->imageData;data[i*step + j] = 111;//  对多通道字节图像:IplImage* src = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 3);int height = src->height;int width = src->width;int step = src->widthStep / sizeof(uchar);int channels = src->nChannels;uchar* data = (uchar *)src->imageData;data[i*step + j*channels + k] = 111;//  对多通道浮点图像(假设用4字节调整) :IplImage* src = cvCreateImage(cvSize(640, 480), IPL_DEPTH_32F, 3);int height = src->height;int width = src->width;int step = src->widthStep / sizeof(float);int channels = src->nChannels;float * data = (float *)src->imageData;data[i*step + j*channels + k] = 111;

3、Mat介绍

具体介绍内容详解我的:。里面有Mat简介,常用成员,构造函数以及三种图像类型格式的转换。

二、哈哈镜介绍

1、原理

哈哈镜是表面凸凹不平的镜面,反映人像及物件的扭曲面貌,令人发笑,故名叫哈哈镜。哈哈镜的原理是曲面镜引起的不规则光线反射与聚焦,做成散乱的影像。镜面扭曲的情况不同,成像的效果也会相异。 常见的变换效果有高矮胖瘦四种效果,镜面材质有金属哈哈镜,玻璃哈哈镜等。

对应到物理中,哈哈镜其实是光的折射,可以理解为数学中的映射,不同的映射会有不同的效果,如线性映射会产生放大缩小的感觉,凸函数则会是凸透镜,凹函数就是凹透镜,原则上,不同的函数就不会产生不同的结果。

所以如果希望通过opencv来做哈哈镜,就需要找到一个对应的映射,让图像的像素扭曲,从而实现哈哈效果。在这里,实现了放大镜和缩小镜。

2、实现

我希望实现的是实时将视频图像卡通化,所以需要通过opencv调用摄像头,并对其进行一系列设置。在这里,采用了最简单的调用摄像头的方式:

VideoCapture capture;capture.open(0);

   获取到每一帧的图像后,需要对图像做一定的处理,因为用了两种方式做处理分别得到:放大镜,缩小镜。所以在处理之前加一个整形变量,允许用户输入,自由选择处理方式,为了防止用户非法输入,我设置循环做判断。输入合法后才允许执行下面的代码。并通过Switch语句设置两种处理方式。代码如下:

int mode = -1;//动画处理模式	cout << "请输入类型:";	cin >> mode;	while (mode<0 || mode >= 2)	{		cout << "处理模式输入错误,请重新输入:";		cin >> mode;	}	switch (mode)	{	case 0:		while (1)		{			capture >> hahaFrame;			hahaFrame.copyTo(img);			magnifyGlass(hahaFrame,img);			imshow("【放大镜】", img);			waitKey(30);		}		break;	case 1:		while (1)		{			capture >> hahaFrame;			hahaFrame.copyTo(img);			compressGlass(hahaFrame,img);			imshow("【压缩镜】", img);			waitKey(30);		}		break;	default:		break;	}

接下来就是最核心的算法,即映射了。

在前面我们说到,所谓哈哈镜,就是图像像素点位置的变化,所以我们要获取到每个像素点的像素值,然后对像素点做操作。

3、凸透镜算法

void magnifyGlass(Mat hahaFrame,Mat img) {	//【1】凸透镜	int width = hahaFrame.cols;	int heigh = hahaFrame.rows;	Point center(width / 2, heigh / 2);	int R = sqrtf(width*width + heigh*heigh) / 2; //直接关系到放大的力度,与R成正比;  	for (int y = 0; y < heigh; y++)	{		uchar *img_p = img.ptr
(y);//定义一个指针,指向第y列,从而可以访问行数据。 for (int x = 0; x < width; x++) { int dis = norm(Point(x, y) - center);//获得当前点到中心点的距离 if (dis < R)//设置变化区间 { int newX = (x - center.x)*dis / R + center.x; int newY = (y - center.y)*dis / R + center.y; img_p[3 * x] = hahaFrame.at
(newY, newX * 3); img_p[3 * x + 1] = hahaFrame.at
(newY, newX * 3 + 1); img_p[3 * x + 2] = hahaFrame.at
(newY, newX * 3 + 2); } } }}

4、凹透镜算法

void compressGlass(Mat hahaFrame,Mat img) {	//【2】凹透镜	int width = hahaFrame.cols;	int heigh = hahaFrame.rows;	Point center(width / 2, heigh / 2);	for (int y = 0; y
(y); for (int x = 0; x
= width) newX = width - 1; if (newY<0) newY = 0; else if (newY >= heigh) newY = heigh - 1; img_p[3 * x] = hahaFrame.at
(newY, newX * 3); img_p[3 * x + 1] = hahaFrame.at
(newY, newX * 3 + 1); img_p[3 * x + 2] = hahaFrame.at
(newY, newX * 3 + 2); } }}

 

转载地址:http://afyni.baihongyu.com/

你可能感兴趣的文章
IBM WebSphere Commerce Analyzer
查看>>
Unix + OS IBM Aix FTP / wu-ftp / proftp
查看>>
my read work
查看>>
db db2 base / instance database tablespace container
查看>>
hd disk / disk raid / disk io / iops / iostat / iowait / iotop / iometer
查看>>
project ASP.NET
查看>>
db db2_monitorTool IBM Rational Performace Tester
查看>>
OS + Unix Aix telnet
查看>>
IBM Lotus
查看>>
Linux +Win LAMPP Tools XAMPP 1.7.3 / 5.6.3
查看>>
my read_university
查看>>
network manager
查看>>
OS + Linux Disk disk lvm / disk partition / disk mount / disk io
查看>>
RedHat + OS CPU、MEM、DISK
查看>>
net TCP/IP / TIME_WAIT / tcpip / iperf / cain
查看>>
webServer kzserver/1.0.0
查看>>
OS + Unix IBM Aix basic / topas / nmon / filemon / vmstat / iostat / sysstat/sar
查看>>
my ReadMap subway / metro / map / ditie / gaotie / traffic / jiaotong
查看>>
OS + Linux DNS Server Bind
查看>>
linux下安装django
查看>>