【原创】【OpenCV】图像的特效变换扭曲变换、球形变换、波动变换
扭曲变换、球形变换、波动变换
话不多说,林忠老师的课设,上学期做的,本着造福广大学弟学妹的想法,就把我的代码放出来吧
为什么每个变换三张图象?因为opencv自带了线性插值函数,我调用函数是一张图片,此外,我还手写了线性插值函数。
嗷对了,这个变换坐标都是有公式的,你把公式翻译成代码就行了
代码如下,每个变换三个结果
//#include "opencv2/highgui/highui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <math.h>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgproc/types_c.h"
#include <opencv2/highgui/highgui_c.h>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs/legacy/constants_c.h"
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
#define pi 3.1415926
//7*9 box filter
void NiuQu(const unsigned char src_data[], unsigned char dst_data[], int cols, int rows, unsigned char dst12_data[])
{
printf("请输入图像扭曲程度0-100:\n");
int niuqu;
cin >> niuqu;
Mat src2, map_x, map_y, dst13;
src2 = imread("D:\\111.bmp", CV_LOAD_IMAGE_GRAYSCALE);
src2.copyTo(dst13);
map_x.create(src2.size(), CV_32FC1);
map_y.create(src2.size(), CV_32FC1);
int i, j, m, n, sum, dx, dy, xc, yc, xs, ys, num;
float r, beta, alpha;
float rmax;
rmax = sqrt(cols * cols + rows * rows);
alpha = niuqu / 20.0;
xc = rows / 2;
yc = cols / 2;
num = 0;
for (i = 0; i < rows; ++i)
{
for (j = 0; j < cols; ++j)
{
dx = j - xc;
dy = i - yc;
r = sqrt(dx * dx + dy * dy);
beta = atan2(dx, dy) + alpha * ((rmax - r) / rmax);//alpha为输入参数/20后的结果
num++;
if (r <= rmax)
{
xs = xc + r * cos(beta);
ys = yc + r * sin(beta);
if ((xs >= 0 && xs <= rows) && (ys >= 0 && ys <= cols))
{
dst_data[(i * cols) + j] = src_data[ys * cols + xs];
map_x.at<float>(i, j) = static_cast<float>(xs);
map_y.at<float>(i, j) = static_cast<float>(ys);
}
else
dst_data[(i * cols) + j] = 0;
}
else
{
dst_data[(i * cols) + j] = src_data[i * cols + j];
map_x.at<float>(i, j) = static_cast<float>(j);
map_y.at<float>(i, j) = static_cast<float>(i);
}
}
}
remap(src2, dst13, map_x, map_y, INTER_LINEAR);
char* avg_window13 = "扭曲图像3";
namedWindow(avg_window13, CV_WINDOW_AUTOSIZE);
imshow(avg_window13, dst13);
float dxs, dys, xss, yss, r1, r2, finalr;
for (i = 1; i < rows - 1; ++i)
{
for (j = 1; j < cols - 1; ++j)
{
dxs = j - xc;
dys = i - yc;
r = sqrt(dxs * dxs + dys * dys);
beta = atan2(dxs, dys) + alpha * ((rmax - r) / rmax);
if (r <= rmax)
{
xss = xc + r * cos(beta);
yss = yc + r * sin(beta);
xs = (int)xss;
ys = (int)yss;
if ((xs >= 0 && xs <= rows) && (ys >= 0 && ys <= cols))
{
r1 = src_data[(ys)* cols + xs] + ((xss - xs) / (xs + 1 - xs)) * (src_data[(ys)* cols + xs + 1] - src_data[(ys)* cols + xs]);
r2 = src_data[(ys + 1) * cols + xs] + ((xss - xs) / (xs + 1 - xs)) * (src_data[(ys + 1) * cols + xs + 1] - src_data[(ys + 1) * cols + xs]);
finalr = r1 + ((yss - ys) / (ys + 1 - ys)) * (r1 - r2);
dst12_data[(i * cols) + j] = cvRound(finalr);
}
else
dst_data[(i * cols) + j] = 0;
}
}
}
}
//7*9 box filter by splitted way
void BoDong(const unsigned char src_data[], unsigned char dst_data[], int cols, int rows, unsigned char dst22_data[])
{
Mat src2, map_x, map_y, dst13;
src2 = imread("D:\\111.bmp", CV_LOAD_IMAGE_GRAYSCALE);
src2.copyTo(dst13);
map_x.create(src2.size(), CV_32FC1);
map_y.create(src2.size(), CV_32FC1);
printf("请输入图像波动振幅程度0-100:\n");
int niuqu;
cin >> niuqu;
printf("请输入图像波动周期程度0-100:\n");
int zhenfu;
cin >> zhenfu;
int zhenfu2 = zhenfu / 10;
Mat dst2;
int i, j, m, n, sum, dx, dy, xc, yc, xs, ys, num;
float r, beta, alpha;
float rmax;
rmax = sqrt(cols * cols + rows * rows);
alpha = niuqu / 20.0;
num = 0;
for (i = 0; i < rows; ++i)
{
for (j = 0; j < cols; ++j)
{
xs = j + alpha * sin(2 * pi * i / (50 * zhenfu2) * pi);//输入周期参数除以20再乘以50后的结果是多少个PI
ys = i + alpha * sin(2 * pi * j / (50 * zhenfu2) * pi);//alpha为振幅参数
dst_data[(i * cols) + j] = src_data[ys * cols + xs];
map_x.at<float>(i, j) = static_cast<float>(xs);
map_y.at<float>(i, j) = static_cast<float>(ys);
}
}
remap(src2, dst13, map_x, map_y, INTER_LINEAR);
char* avg_window13 = "波动图像3";
namedWindow(avg_window13, CV_WINDOW_AUTOSIZE);
imshow(avg_window13, dst13);
float dxs, dys, xss, yss, r1, r2, finalr;
for (i = 0; i < rows; ++i)
{
for (j = 0; j < cols; ++j)
{
xss = j + alpha * sin(2 * pi * i / (50 * zhenfu2) * pi);
yss = i + alpha * sin(2 * pi * j / (50 * zhenfu2) * pi);
xs = (int)xss;
ys = (int)yss;
r1 = src_data[(ys)* cols + xs] + ((xss - xs) / (xs + 1 - xs)) * (src_data[(ys)* cols + xs + 1] - src_data[(ys)* cols + xs]);
r2 = src_data[(ys + 1) * cols + xs] + ((xss - xs) / (xs + 1 - xs)) * (src_data[(ys + 1) * cols + xs + 1] - src_data[(ys + 1) * cols + xs]);
finalr = r1 + ((yss - ys) / (ys + 1 - ys)) * (r1 - r2);
dst22_data[(i * cols) + j] = cvRound(finalr);
}
}
}
//5*5 weighted avg filter
void QiuXing(const unsigned char src_data[], unsigned char dst_data[], int cols, int rows, unsigned char dst32_data[])
{
Mat src2, map_x, map_y, dst13;
src2 = imread("D:\\111.bmp", CV_LOAD_IMAGE_GRAYSCALE);
src2.copyTo(dst13);
map_x.create(src2.size(), CV_32FC1);
map_y.create(src2.size(), CV_32FC1);
printf("请输入球形变换透镜折射率:\n");
float niuqu;
cin >> niuqu;
printf("请输入球形变换透镜半径程度(0-100):\n");
float banjing;
cin >> banjing;
int i, j, m, n, sum, dx, dy, xc, yc, xs, ys, num;
float r, betax, betay, alpha, z;
float rmax;
rmax = sqrt(cols * cols + rows * rows) / 2 * (banjing / 100);//半径为图像最大半径除以四再乘以(输入参数除以40)
alpha = niuqu;
xc = rows / 2;
yc = cols / 2;
num = 0;
for (i = 0; i < rows; ++i)
{
for (j = 0; j < cols; ++j)
{
dx = i - xc;
dy = j - yc;
r = sqrt(dx * dx + dy * dy);
z = sqrt(rmax * rmax - r * r);
float thetax = sqrt(dx * dx + z * z);
float thetay = sqrt(dy * dy + z * z);
betax = (1 - (1 / alpha)) * asin(dx / thetax);
betay = (1 - (1 / alpha)) * asin(dy / thetay);
num++;
if (r <= rmax)
{
xs = i - z * tan(betax);
ys = j - z * tan(betay);
dst_data[(i * cols) + j] = src_data[xs * cols + ys];
map_x.at<float>(i, j) = static_cast<float>(ys);
map_y.at<float>(i, j) = static_cast<float>(xs);
}
else
{
xs = i;
ys = j;
dst_data[(i * cols) + j] = src_data[i * cols + j];
map_x.at<float>(i, j) = static_cast<float>(j);
map_y.at<float>(i, j) = static_cast<float>(i);
}
}
}
remap(src2, dst13, map_x, map_y, INTER_LINEAR);
char* avg_window13 = "球形变换3";
namedWindow(avg_window13, CV_WINDOW_AUTOSIZE);
imshow(avg_window13, dst13);
float dxs, dys, xss, yss, r1, r2, finalr;
for (i = 0; i < rows; ++i)
{
for (j = 0; j < cols; ++j)
{
dx = i - xc;
dy = j - yc;
r = sqrt(dx * dx + dy * dy);
z = sqrt(rmax * rmax - r * r);
float thetax = sqrt(dx * dx + z * z);
float thetay = sqrt(dy * dy + z * z);
betax = (1 - (1 / alpha)) * asin(dx / thetax);
betay = (1 - (1 / alpha)) * asin(dy / thetay);
num++;
if (r <= rmax)
{
xss = i - z * tan(betax);
yss = j - z * tan(betay);
xs = (int)xss;
ys = (int)yss;
r1 = src_data[(ys)* cols + xs] + ((yss - ys) / (ys + 1 - ys)) * (src_data[(ys)* cols + xs + 1] - src_data[(ys)* cols + xs]);
r2 = src_data[(ys + 1) * cols + xs] + ((yss - ys) / (ys + 1 - ys)) * (src_data[(ys + 1) * cols + xs + 1] - src_data[(ys + 1) * cols + xs]);
finalr = r1 + ((xss - xs) / (xs + 1 - xs)) * (r1 - r2);
dst32_data[(j * cols) + i] = cvRound(finalr);
}
else
{
xs = j;
ys = i;
dst32_data[(i * cols) + j] = src_data[i * cols + j];
}
}
}
}
int main(int argc, char** argv)
{
Mat src, dst, dst2, dst3, dst4, dst12, dst22, dst32;
char* source_window = "Source image";
char* avg_window1 = "扭曲图像";
char* avg_window12 = "扭曲图像2";
char* avg_window2 = "波动图像";
char* avg_window22 = "波动图像2";
char* avg_window_weighted = "球形变换";
char* avg_window_weighted2 = "球形变换2";
/// Load image
src = imread("D:\\111.bmp", CV_LOAD_IMAGE_GRAYSCALE);
if (!src.data)
{
cout << "not find source image" << endl;
return -1;
}
namedWindow(source_window, CV_WINDOW_AUTOSIZE);
imshow(source_window, src);
if (src.isContinuous())
{
src.copyTo(dst); src.copyTo(dst3); src.copyTo(dst4);
dst.copyTo(dst2);
dst.copyTo(dst12);
dst.copyTo(dst22);
dst.copyTo(dst32);
//扭曲变换
double t = (double)getTickCount();
NiuQu(src.data, dst.data, src.cols, src.rows, dst12.data);
transpose(dst, dst2);
t = ((double)getTickCount() - t) / getTickFrequency();
cout << "Times passed in seconds: " << t << endl;
namedWindow(avg_window1, CV_WINDOW_AUTOSIZE);
imshow(avg_window1, dst);
namedWindow(avg_window12, CV_WINDOW_AUTOSIZE);
imshow(avg_window12, dst12);
//波动变换
src.copyTo(dst);
t = (double)getTickCount();
BoDong(src.data, dst.data, src.cols, src.rows, dst22.data);
t = ((double)getTickCount() - t) / getTickFrequency();
cout << "Times passed in seconds: " << t << endl;
namedWindow(avg_window2, CV_WINDOW_AUTOSIZE);
imshow(avg_window2, dst);
namedWindow(avg_window22, CV_WINDOW_AUTOSIZE);
imshow(avg_window22, dst22);
//球星变换
src.copyTo(dst);
QiuXing(src.data, dst.data, src.cols, src.rows, dst32.data);
namedWindow(avg_window_weighted, CV_WINDOW_AUTOSIZE);
imshow(avg_window_weighted, dst);
namedWindow(avg_window_weighted2, CV_WINDOW_AUTOSIZE);
imshow(avg_window_weighted2, dst32);
}
waitKey(0);
return 0;
}
什么?你说解释在哪里?
打字好麻烦,你们看不懂就直接问我吧