【OpenCV】图像的特效变换扭曲变换、球形变换、波动变换

本文深入探讨了使用OpenCV实现的图像特效变换,包括扭曲变换、球形变换和波动变换。通过详细代码示例,展示了如何调整变换参数以实现不同的视觉效果,适用于图像处理初学者和进阶者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【原创】【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;
}

什么?你说解释在哪里?

打字好麻烦,你们看不懂就直接问我吧

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值