2021-04-03 计算机视觉


要求(减色)

对以下减色方法进行测试,比较其运行时间。

方法1:使用整数除法

方法2:使用取模运算符方法

方法3:使用位运算符方法

方法4:使用整数除法和迭代器方法

方法5:使用整数除法和at方法


一、减色过程简要

通过一定的减色算法将图像中每个像素的每个通道的值同时减少
例如:
24位彩色图像颜色总数为256×256×256
如果把每种颜色数量减少到1/8,那么颜色总数就变成32×32×32

二、代码

main函数

#include <iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  

using namespace cv;
//减色算法函数处
int main()
{
	Mat image = imread("01.jpg");
	printf("整数:%lf\n",Co_Red_Div(image));
	printf("取模:%lf\n",Co_Red_Mod(image));
	printf("位运算:%lf\n",Co_Red_Bit(image));
	printf("整数—迭代器:%lf\n", Co_Red_Div_Iter(image));
	printf("整数—at:%lf\n", Co_Red_Div_At(image));
	waitKey(0);
	return 0;
}

方法1:使用整数除法

代码如下(示例):

//整数除法
double Co_Red_Div(Mat image, int div = 64) {
	double start = getTickCount();//返回从最近一次电脑开机到当前的时钟周期
	int nr = image.rows;
	int nc = image.cols*image.channels();
	for (int j = 0; j < nr; j++) {
		uchar* data = image.ptr<uchar>(j);
		for (int i = 0; i < nc; i++) {
			data[i] = saturate_cast<uchar>(
				data[i] / div * div + div / 2
				);
		}
	}
	//imshow("整数", image);
	//cv::getTickFrequency()返回每秒的时钟周期数
	return (getTickCount() - start) / getTickFrequency();//计算s
}

方法2:使用取模运算符方法

代码如下(示例):

//取模
double Co_Red_Mod(Mat image, int div = 64) {
	double start = getTickCount();
	int nr = image.rows;
	int nc = image.cols*image.channels();
	for (int j = 0; j < nr; j++) {
		uchar* data = image.ptr<uchar>(j);
		for (int i = 0; i < nc; i++) {
			data[i] = data[i] -
				data[i] % div + div / 2;
		}
	}
	//imshow("整数", image);
	return (getTickCount() - start) / getTickFrequency();
}

方法3:使用位运算符方法

减色因子要限定为2的指数,即 div=pow(2,n)

代码如下(示例):

//位运算
double Co_Red_Bit(Mat image, int div = 16) {
	double start = getTickCount();
	int nr = image.rows;
	int nc = image.cols*image.channels();
	for (int j = 0; j < nr; j++) {
		uchar* data = image.ptr<uchar>(j);
		for (int i = 0; i < nc; i++) {
		//用来截取像素值的掩码
			uchar mask = uchar(0xFF) << 4;//我这div是16,所以为mask0xF0,n=4
			*data &= mask;
			*data++ += uchar(div) >> 1;
		}
	}
	//imshow("整数", image);
	return (getTickCount() - start) / getTickFrequency();
}

方法4:使用整数除法和迭代器方法

代码例如:

//整数—迭代器
double Co_Red_Div_Iter(Mat image, int div = 64) {
	double start = getTickCount();
	MatIterator_<Vec3b> begin = image.begin<Vec3b>();
	MatIterator_<Vec3b> end = image.end<Vec3b>();
	for (; begin != end; begin++) {
		(*begin)[0] = saturate_cast<uchar>(
			(*begin)[0] / div * div + div / 2);
		(*begin)[1] = saturate_cast<uchar>(
			(*begin)[1] / div * div + div / 2);
		(*begin)[2] = saturate_cast<uchar>(
			(*begin)[2] / div * div + div / 2);
	}
	//imshow("整数", image);
	return (getTickCount() - start) / getTickFrequency();
}

方法5:使用整数除法和at方法

代码例如:

//整数除法-at方法
double Co_Red_Div_At(Mat image, int div = 64) {
	double start = getTickCount();
	int nr = image.rows;
	int nc = image.cols;
	for (int j = 0; j < nr; j++) {
		for (int i = 0; i < nc; i++) {
			image.at<Vec3b>(j,i)[0]=saturate_cast<uchar>(
				image.at<Vec3b>(j, i)[0] / div * div + div / 2
				);
			image.at<Vec3b>(j, i)[1] = saturate_cast<uchar>(
				image.at<Vec3b>(j, i)[1] / div * div + div / 2
				);
			image.at<Vec3b>(j, i)[2] = saturate_cast<uchar>(
				image.at<Vec3b>(j, i)[2] / div * div + div / 2
				);
		}
	}
	//imshow("整数", image);
	return (getTickCount() - start) / getTickFrequency();
}


三 运行结果

结果
以上算法可能存在越界 用 cv::saturate_cast()


要求(简单的图像运算)

任务1:在网上找两幅图像,其中一幅为雨景图,利用两幅图像的混合产生下雨效果,显示两幅原图以及混合后的图像;

任务2:修改图像亮度,修改任务1结果图像的亮度,并显示结果图像(窗口命名为“增加亮度”或“降低亮度”)

任务3:仍然采用任务1的两幅图像,利用分割与合并图像通道将雨景图加到某个通道上(注意此时雨景图要以灰度图形式读入),并显示处理结果,窗口名为(“x通道叠加效果”,x为红色或绿色或蓝色)


一,简要

图像和普通的矩阵一样可以进行加,减,乘,除运算,因此可以用不同的方式来组合图像

二,代码

#include <iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int main()
{
	Mat image = imread("01.jpg");
	Mat image1 = imread("xiaYu.jpg");
	if (image.size() != image1.size())
		resize(image1,image1,image.size());
	imshow("image", image);
	imshow("image1", image1);
	Mat result;
	//输出混合图
	addWeighted(image, 0.7, image1, 0.9, 0, result);
	imshow("result", result);
	//改变亮度
	imshow("降低亮度", result + Scalar(-50, -50, -50));
	imshow("增加亮度", result + Scalar(50, 50, 50));
	//通道叠加混合图
	/*Mat image3 = imread("xiaYu.jpg", IMREAD_GRAYSCALE);
	imshow("image3", image3);*/
	Mat image2;
	//opencv 直接读入的单通道和cvtColor的值不同
	//直接读入  可 0 或 IMREAD_GRAYSCALE
	//cvtColor  COLOR_RGB2GRAY 或 CV_BGR2GRAY
	//改变为灰度图,为单通道
	cvtColor(image1, image2, COLOR_RGB2GRAY);
	//创建包含不同通道的向量
	vector<Mat> planes;
	//分隔
	split(image, planes);
	//单通道相加
	planes[2] += image2;
	//所有通道合拼
	merge(planes, result);
	imshow("红色通道叠加效果", result);
	waitKey(0);
	return 0;
}

三,运行结果

在这里插入图片描述


要求(简单的图像映射)

利用图像重映射实现任意角度的图像旋转,显示出原图和旋转后的图像(多个不同角度)

一,简要

通过移动像素来改变图像的外观

二,代码

#include <iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include<opencv2/opencv.hpp>
#include <cmath>
#define j2h(x) (3.1415926 * (x) / 180.0)
using namespace cv;
using namespace std;

//波浪效果
void wave(const Mat &image, Mat &result) {
	Mat srcX(image.rows, image.cols, CV_32F);
	Mat srcY(image.rows, image.cols, CV_32F);
	for (int i = 0; i < image.rows; i++) {
		float* pSrcX = srcX.ptr<float>(i);
		float* pSrcY = srcY.ptr<float>(i);
		for (int j = 0; j < image.cols; j++) {
			pSrcX[j] = j;
			pSrcY[j] = i + 5 * sin(j / 10.0);
		}
	}
	remap(image, result, srcX, srcY, INTER_LINEAR);
}

//水平翻转效果
void waveF(const Mat &image, Mat &result) {
	Mat srcX(image.rows, image.cols, CV_32F);
	Mat srcY(image.rows, image.cols, CV_32F);
	for (int i = 0; i < image.rows; i++) {
		float* pSrcX = srcX.ptr<float>(i);
		float* pSrcY = srcY.ptr<float>(i);
		for (int j = 0; j < image.cols; j++) {
			pSrcX[j] = image.cols-j-1;
			pSrcY[j] = i;
		}
	}
	remap(image, result, srcX, srcY, INTER_LINEAR);
}

//旋转效果
void waveX(const Mat &image, Mat &result, double angle) {
	Mat srcX(image.rows, image.cols, CV_32F);
	Mat srcY(image.rows, image.cols, CV_32F);
	int cenx ,ceny;
	double sinValue = sin(j2h(angle));
	double cosValue = cos(j2h(angle));
	for (int i = 0; i < image.rows; i++) {
		float* pSrcX = srcX.ptr<float>(i);
		float* pSrcY = srcY.ptr<float>(i);
		for (int j = 0; j < image.cols; j++) {
			cenx = j - image.cols / 2;
			ceny = i - image.rows / 2;
			pSrcX[j] = cenx * cosValue + ceny * sinValue +
				image.cols / 2;
			pSrcY[j] = ceny * cosValue - cenx * sinValue +
				image.rows / 2;
		}
	}
	
	remap(image, result, srcX, srcY, INTER_LINEAR);
}

int main()
{
	Mat image = imread("01.jpg");
	Mat result;
	//wave(image, result);
	//waveF(image, result);
	waveX(image, result,-60);
	imshow("波浪形", result);
	waitKey(0);
	return 0;
}

三,运行结果

搜索

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值