OpenCV C++案例十六,哈哈镜图像及去水印

共 8652字,需浏览 18分钟

 ·

2022-06-17 18:42

关注涛涛CV,设置星标,更新错过




作者Zero___Chen

来源blog.csdn.net/Zero___Chen

本文将使用OpenCV C++ 制作哈哈镜图像。


其实原理很简单,就是让图像像素扭曲,将像素重新进行映射。

假设输入图像宽w,高h。图像中心点坐标(cx,cy),图像任意像素点(x,y)到中心点距离 dx=(x-cx),dy=(y-cy),变换半径r。


一、凸透镜

制作凸透镜效果(将图像放大)。根据网上查找的变换公式:

      图像放大:凸透镜      x = (dx / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / r) + cx;      y = (dy / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / r) + cy;


1.功能源码

请查看源码注释

bool Mirror_Magnify(Mat src){      /*           图像放大:凸透镜      x = (dx / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / r) + cx;      y = (dy / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / r) + cy;      */
Mat canvas = Mat::zeros(src.size(), src.type()); //画布,重新生成哈哈图像 //图像中心 int cx = src.cols / 2; int cy = src.rows / 2; //决定哈哈镜大小 int radius = 200;

//图像像素修改 for (int i = 0; i < src.rows; i++) { for (int j = 0; j < src.cols; j++) { //任意像素点到图像中心距离 int dx = j - cx; int dy = i - cy; //重新映射像素点位置 int x = (dx / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / radius) + cx; int y = (dy / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / radius) + cy;

for (int c = 0; c < 3; c++) { //防止越界 if ((x > 0 && x < src.cols) && (y > 0 && y < src.rows)) { canvas.at(i, j)[c] = src.at(y, x)[c]; } } }      }      imshow("Mirror_Magnify", canvas); return true;}


2.效果显示


二、凹透镜

制作凹透镜效果(将图像缩小)。根据网上查找的变换公式:


      图像缩小:凹透镜      x = sqrt(sqrt(pow(dx, 2) + pow(dy, 2))) * compress * cos(atan2(dy, dx)) + cx;      y = sqrt(sqrt(pow(dx, 2) + pow(dy, 2))) * compress * sin(atan2(dy, dx)) + cy;


1.功能源码

请查看源码注释

bool Mirror_Narrow(Mat src){  /*  图像缩小:凹透镜  x = sqrt(sqrt(pow(dx, 2) + pow(dy, 2))) * compress * cos(atan2(dy, dx)) + cx;  y = sqrt(sqrt(pow(dx, 2) + pow(dy, 2))) * compress * sin(atan2(dy, dx)) + cy;  */
Mat canvas = Mat::zeros(src.size(), src.type());//画布,重新生成哈哈图像
int compress = 12; //压缩强度 //图像中心 int cx = src.cols / 2; int cy = src.rows / 2;
//图像像素修改 for (int i = 0; i < src.rows; i++) { for (int j = 0; j < src.cols; j++) { //任意像素点到图像中心距离 int dx = j - cx; int dy = i - cy; //重新映射像素点位置 int x = sqrt(sqrt(pow(dx, 2) + pow(dy, 2))) * compress * cos(atan2(dy, dx)) + cx; int y = sqrt(sqrt(pow(dx, 2) + pow(dy, 2))) * compress * sin(atan2(dy, dx)) + cy;
for (int c = 0; c < 3; c++) { //防止越界 if ((x > 0 && x < src.cols) && (y > 0 && y < src.rows)) { canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(y, x)[c]; } } }  }  imshow("Mirror_Narrow", canvas); return true;}


2.效果显示


三、源码

#include<iostream>#include<opencv2/opencv.hpp>using namespace std;using namespace cv;
/* 哈哈镜实现原理:让图像像素扭曲,将像素重新进行映射 假设输入图像宽w,高h。图像中心点坐标(cx,cy),图像任意像素点(x,y)到中心点距离 dx=(x-cx),dy=(y-cy),变换半径r*/

bool Mirror_Magnify(Mat src){ /* 图像放大:凸透镜 x = (dx / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / r) + cx; y = (dy / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / r) + cy; */
Mat canvas = Mat::zeros(src.size(), src.type()); //画布,重新生成哈哈图像
//图像中心 int cx = src.cols / 2; int cy = src.rows / 2; //决定哈哈镜大小 int radius = 200;
//图像像素修改 for (int i = 0; i < src.rows; i++) { for (int j = 0; j < src.cols; j++) { //任意像素点到图像中心距离 int dx = j - cx; int dy = i - cy; //重新映射像素点位置 int x = (dx / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / radius) + cx; int y = (dy / 2)*(sqrt(pow(dx, 2) + pow(dy, 2)) / radius) + cy;
for (int c = 0; c < 3; c++) { //防止越界 if ((x > 0 && x < src.cols) && (y > 0 && y < src.rows)) { canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(y, x)[c]; } } } }
imshow("Mirror_Magnify", canvas);
return true;}

bool Mirror_Narrow(Mat src){ /* 图像缩小:凹透镜 x = sqrt(sqrt(pow(dx, 2) + pow(dy, 2))) * compress * cos(atan2(dy, dx)) + cx; y = sqrt(sqrt(pow(dx, 2) + pow(dy, 2))) * compress * sin(atan2(dy, dx)) + cy; */
Mat canvas = Mat::zeros(src.size(), src.type());//画布,重新生成哈哈图像
int compress = 12; //压缩强度 //图像中心 int cx = src.cols / 2; int cy = src.rows / 2;
//图像像素修改 for (int i = 0; i < src.rows; i++) { for (int j = 0; j < src.cols; j++) { //任意像素点到图像中心距离 int dx = j - cx; int dy = i - cy; //重新映射像素点位置 int x = sqrt(sqrt(pow(dx, 2) + pow(dy, 2))) * compress * cos(atan2(dy, dx)) + cx; int y = sqrt(sqrt(pow(dx, 2) + pow(dy, 2))) * compress * sin(atan2(dy, dx)) + cy;
for (int c = 0; c < 3; c++) { //防止越界 if ((x > 0 && x < src.cols) && (y > 0 && y < src.rows)) { canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(y, x)[c]; } } } }
imshow("Mirror_Narrow", canvas);
return true;}

int main(){ Mat src = imread("test.jpg"); if (src.empty()) { cout << "No Image!" << endl; system("pause"); return -1; }
Mirror_Magnify(src); Mirror_Narrow(src);
imshow("test", src); waitKey(0); system("pause");; return 0;}

总结

本文使用OpenCV C++ 制作哈哈镜图像,关键步骤有以下几点。

1、了解哈哈镜图像制作原理:根据公式对图像像素进行重新映射。




本文将使用OpenCV C++ 进行简单图像水印去除。

我们在网上download图片时,经常因为版权问题有水印。本案例通过编写算法进行简单水印去除。


一、水印定位

如图所示,图像左下角、右下角有水印。第一步,我们首先得定位水印所在位置。


      Mat gray;      cvtColor(src, gray, COLOR_BGR2GRAY);      //图像二值化,筛选出白色区域部分      Mat thresh;      threshold(gray, thresh, 220, 255, THRESH_BINARY);

如图为二值化后得到的效果图。接下来,我们需要提取水印区域的像素。


      //提取图片下方的水印,制作掩模图像      Mat mask = Mat::zeros(src.size(), CV_8U);      int height = src.rows;      int width = src.cols;      int start = 0.9*height;      //遍历图像像素,提取出水印部分像素,制作掩模图像      for (int i = start; i < height; i++)      {            uchar*data = thresh.ptr(i);            for (int j = 0; j < width; j++)            {                  if (data[j] == 255)                  {                        mask.at(i, j) = 255;                                    }                              }      }


如图所示,至此我们已经得到水印部分的二值掩模图像。接下来,使用OpenCV 内置inpaint API进行图像像素修复。


二、图像修复


      //使用inpaint进行图像修复      Mat result;      inpaint(src, mask, result, 1, INPAINT_NS);

如图所示,这是直接使用提取出的二值掩模进行图像修复得到的结果,可以看出效果不是很好。原因是,提取出来的掩模未能覆盖完全待修复像素。故我们需要将掩模图像进行膨胀操作,扩大掩模范围。



      //将掩模进行膨胀,使其能够覆盖图像更大区域      Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));      dilate(mask, mask, kernel);

如图为进行膨胀过后的掩模图像。这时,我们使用这张掩模图像再进行图像修复工作,得到效果如图所示。


三、效果显示


四、源码

#include<iostream>#include<opencv2/opencv.hpp>using namespace std;using namespace cv;
/*void inpaint( InputArray src, 原图 InputArray inpaintMask, 二进制掩模,指示要修复的像素 OutputArray dst, 目标图像 double inpaintRadius, 像素周围的邻域补绘。通常,如果要修复的区域很小,则使用较小的值仅产生较少模糊 int flags INPAINT_NS 或 INPAINT_TELEA )*/
/*图像简单水印去除:定位到水印所在位置,将水印部分提取出来制作二进制掩模图像,使用inpaint API进行图像修复*/
int main(){ Mat src = imread("test.jpg"); if (src.empty()) { cout << "No Image!" << endl; system("pause"); return -1; }
Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY);
//图像二值化,筛选出白色区域部分 Mat thresh; threshold(gray, thresh, 220, 255, THRESH_BINARY);
//提取图片下方的水印,制作掩模图像 Mat mask = Mat::zeros(src.size(), CV_8U); int height = src.rows; int width = src.cols; int start = 0.9*height; //遍历图像像素,提取出水印部分像素,制作掩模图像 for (int i = start; i < height; i++) { uchar*data = thresh.ptr<uchar>(i); for (int j = 0; j < width; j++) { if (data[j] == 255) { mask.at<uchar>(i, j) = 255; } } }
//将掩模进行膨胀,使其能够覆盖图像更大区域 Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5)); dilate(mask, mask, kernel);
//使用inpaint进行图像修复 Mat result; inpaint(src, mask, result, 1, INPAINT_NS);
imshow("mask", mask); imshow("test", result); waitKey(0); system("pause"); return 0;}


总结

本文使用OpenCV C++ 进行简单图像水印去除,关键步骤有以下几点。

1、定位水印位置,制作二值掩模图像。

2、进行图像像素修复。



总结:

10年机器视觉网站,5年人工智能网站

2019经历总结2018视觉总结

项目感悟赚钱思路项目视频

课程:

《机器视觉:应用讲解》一总体概述二相机篇三镜头篇四光源篇五光学系统选型六视觉开发软件七相机标定技术八项目案例解析九视觉公司分析十产业发展情况

笔记:

《智能革命》《人工智能》《AI•未来》《好好赚钱》《韭菜的自我修养》读书笔记

行业: 

服务机器人公司,机器视觉公司,自动驾驶公司,ADAS公司总结, 防疫机器人发展腾讯未来交通

SLAM:

Vslam方案+源码,语义SLAM与深度相机SLAM和导航避障视觉SLAM总结

秦学英《三维物体的识别与跟踪》章国锋《视觉SLAM》申抒含《基于图像的三维建模》姜翰青《RGB -D SLAM》记录笔记

视觉SLAM的建图课件3课件2课件1

机器视觉:

毫米波雷达雷达视觉融合2021视觉研讨会2020上海研讨会双目和激光的三维重建2021视觉市场研究太阳能行业应用

机器视觉基本概念笔记,记录五,记录四,记录三,记录二,记录一

图像处理:

图像处理基本概念笔记,记录八,记录七,记录六 ,记录五,记录四 ,记录三,记录二 ,记录二,记录一

欢迎支持,点击在看,分享

浏览 22
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报