哈哈哈哈哈哈镜~

你。 提交于 2021-01-14 08:02:15

欢迎关注【Opencv视觉实践








我绝对是无聊爆炸了,所以我又丧心病狂处理二次元图片了。

今天基于像素变换来实现图像的哈哈镜变换,效果就是下面这样了:

哈哈镜分两种,一种是挤压,一种是放大。分别对应凹函数和凸函数。

输入一副图像,首先设置缩放中心center,我们取原图鼻子处为中心。

设置图像上任意一点到中心点的相对坐标tx= x-cx,ty=y-cy。

左边为挤压哈哈镜,对应像素映射函数:

//变换后新的坐标x = cos(atan2(ty , tx))* 12*(sqrt(tx*tx + ty*ty))+cxy = sin(atan2(ty , tx))* 12*(sqrt(tx*tx + ty*ty))+cy

公式中的常数12代表强度,越大则图像越扭曲。

自定义挤压函数(C++版)(Python版可以点击文末阅读原文查看):

Mat MinFrame(Mat frame) {  Mat srcImage;  frame.copyTo(srcImage);  int radius = 400;//定义哈哈镜的半径
int height = frame.rows; int width = frame.cols; //图片的长宽 Point2d center;//人脸中心 center.x = 130; center.y = 180;
int newX, newY;//变换后的坐标
for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) { double tX = x - center.x; double tY = y - center.y;
double theta = atan2(tY, tX); radius = sqrt((tX * tX) + (tY * tY)); //与上面一样,计算公式不一样
int newR = sqrt(radius) *8; newX = int(center.x + (newR * cos(theta))); newY = int(center.y + (newR * sin(theta)));
if (newX<0 && newX>width) newX = 0; if (newY<0 && newY>height) newY = 0;
if (newX < width && newY < height) { srcImage.at<Vec3b>(y, x)[0] = frame.at<Vec3b>(newY, newX*3)[0]; //将计算后的坐标移动到原坐标 srcImage.at<Vec3b>(y, x)[1] = frame.at<Vec3b>(newY, newX*3+1)[1]; srcImage.at<Vec3b>(y, x)[2] = frame.at<Vec3b>(newY, newX*3+2)[2]; } else { srcImage.at<Vec3b>(y, x)[0] = frame.at<Vec3b>(y, x)[0]; //将计算后的坐标移动到原坐标 srcImage.at<Vec3b>(y, x)[1] = frame.at<Vec3b>(y, x)[1]; srcImage.at<Vec3b>(y, x)[2] = frame.at<Vec3b>(y, x)[2]; } } return srcImage;}

右边为放大哈哈镜,对应像素映射函数:

//变换后的新坐标x = (tx/2)*(sqrt(tx*tx + ty*ty)/radius)+cxy = (ty/2)*(sqrt(tx*tx + ty*ty)/radius)+cy

自定义放大函数(C++版):

Mat MaxFrame(Mat frame) {  Mat srcImage;  frame.copyTo(srcImage);
int radius = 400;//定义哈哈镜的半径 int height = frame.rows; int width = frame.cols; //图片的长宽 Point2d center;//图片中心 center.x = 130;//人脸中心像素坐标 center.y = 180;
int newX, newY;//变换后的坐标 int real_radius = int(radius / 2.0); //计算公式
for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) { int tX = x - center.x; int tY = y - center.y;
int distance = tX * tX + tY * tY; if (distance < radius*radius) { newX = int(tX / 2.0); newY = int(tY / 2.0);
newX = int(newX * (sqrt(distance) / real_radius)); newY = int(newY * (sqrt(distance) / real_radius));
newX = int(newX + center.x); newY = int(newY + center.y); if (newX < width && newY < height) { srcImage.at<Vec3b>(y, x)[0] = frame.at<Vec3b>(newY, newX)[0]; //将计算后的坐标移动到原坐标 srcImage.at<Vec3b>(y, x)[1] = frame.at<Vec3b>(newY, newX)[1]; srcImage.at<Vec3b>(y, x)[2] = frame.at<Vec3b>(newY, newX)[2]; } } else { srcImage.at<Vec3b>(y, x)[0] = frame.at<Vec3b>(y, x)[0]; //将计算后的坐标移动到原坐标 srcImage.at<Vec3b>(y, x)[1] = frame.at<Vec3b>(y, x)[1]; srcImage.at<Vec3b>(y, x)[2] = frame.at<Vec3b>(y, x)[2]; } } return srcImage;}

至于这俩函数怎么来的,,我也说不出啥门道来,,欢迎评论告知哈。

再看最后一眼:

THE END

欢迎点击下方图片箭头评论哦

本文分享自微信公众号 - Opencv视觉实践(gh_31e12b1be0e0)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!