[C++][opencv]基于opencv实现photoshop算法高反差保留

news2024/9/23 5:32:26

【测试环境】

vs2019

opencv==4.8.0

【效果演示】

【核心代码实现】

Filter.hpp

#ifndef OPENCV2_PHOTOS_FILTER_HPP_
#define OPENCV2_PHOTOS_FILTER_HPP_

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"

namespace cv {

class Filter {
public:
	Filter();
	virtual ~Filter();

	/**
	 * Gaussian Blur
	 *
	 * @param src [in]  InputArray
	 * @param dst [out] OutputArray
	 * @param radius [in] Gaussian radius, value range [0.1, 250]
	 *
	 * @return 0 if success, else return error code
	 */
	static int GaussianBlur(InputArray src, OutputArray dst, float radius);

	/**
	 * High Pass
	 *
	 * @param src [in]  InputArray
	 * @param dst [out] OutputArray
	 * @param radius [in] Gaussian radius, value range [0.1, 250]
	 *
	 * @return 0 if success, else return error code
	 */
	static int HighPass(InputArray src, OutputArray dst, float radius);


	static int AddNoise(InputArray src, OutputArray dst);

	/**
	 * Ripple
	 *
	 * @param src [in]  InputArray
	 * @param dst [out] OutputArray
	 * @param center [in] center point of ripple
	 * @param radius [in] radius of ripple
	 * @param phases [in]
	 * @param waveLength [in] wave length
	 * @param amplitude [in] amplitude
	 *
	 * @return 0 if success, else return error code
	 */
	static int Ripple(InputArray src, OutputArray dst, Point center, float radius,
			float phases = 0, int waveLength = 0, int amplitude = 0);

	/**
	 * Pinch
	 *
	 * @param src [in]  InputArray
	 * @param dst [out] OutputArray
	 *
	 * @return 0 if success, else return error code
	 */
	static int Pinch(InputArray src, OutputArray dst, float amount = 0.5, Point center = Point(0,0), float radius = 0.6 );


	/**
	 * Kaleidoscope
	 *
	 * @param src [in]  InputArray
	 * @param dst [out] OutputArray
	 *
	 * @return 0 if success, else return error code
	 */
	static int Kaleidoscope(InputArray src, OutputArray dst);
};

} /* namespace cv */

#endif /* OPENCV2_PHOTOS_FILTER_HPP_ */

 Filter.cpp

#include "Filter.hpp"
#include <math.h>
#include <iostream>

#define CLIP_RANGE(value, min, max)  ( (value) > (max) ? (max) : (((value) < (min)) ? (min) : (value)) )
#define COLOR_RANGE(value)  CLIP_RANGE((value), 0, 255)
#define M_PI 3.14
namespace cv {

Filter::Filter() {

}

Filter::~Filter() {
}

/**
 * Gaussian Blur
 *
 * @param src [in]  InputArray
 * @param dst [out] OutputArray
 * @param radius [in] Gaussian radius, value range [0.1, 250]
 *
 * @return 0 if success, else return error code
 */
int Filter::GaussianBlur(InputArray src, OutputArray dst, float radius)
{
	if ( radius < 0.1 ) return -1;
	if ( radius > 250 ) return -1;
	cv::GaussianBlur(src, dst, Size(0,0), radius, radius);
	return 0;
}

/**
 * High Pass
 *
 * @param src [in]  InputArray
 * @param dst [out] OutputArray
 * @param radius [in] Gaussian radius, value range [0.1, 250]
 *
 * @return 0 if success, else return error code
 */
int Filter::HighPass(InputArray src, OutputArray dst, float radius)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	dst.create(src.size(), src.type());
	Mat output = dst.getMat();

	if ( radius < 0.1 ) return -1;
	if ( radius > 250 ) return -1;
	cv::GaussianBlur(input, output, Size(0, 0), radius, radius);

	const uchar *in;
	uchar *out;
	int width = input.cols;
	int height = input.rows;
	int channels = input.channels();

	for (int y = 0; y < height; ++y) {
		in = input.ptr<uchar>(y);
		out = output.ptr<uchar>(y);
		for (int x = 0; x < width; ++x) {
			for (int i = 0; i < 3; ++i ) {
				*out = COLOR_RANGE((*in - *out) + 127);
				++out; ++in;
			}

			for (int i = 0; i < channels-3; ++i) {
				*out++ = *in++;
			}
		}
	}
	return 0;
}



int Filter::AddNoise(InputArray src, OutputArray dst)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	dst.create(src.size(), src.type());
	Mat output = dst.getMat();

	//output = input.clone();
	cv::randn(output, 0.5, 0.25);
}

#define PRINT_VAR(a) std::cout << #a << "= " << a << std::endl

/**
 * Ripple
 *
 * @param src [in]  InputArray
 * @param dst [out] OutputArray
 * @param center [in] center point of ripple
 * @param radius [in] radius of ripple
 * @param phases [in]
 * @param waveLength [in] wave length
 * @param amplitude [in] amplitude
 *
 * @return 0 if success, else return error code
 */
int Filter::Ripple(InputArray src, OutputArray dst, Point center, float radius, float phases,
		int wave_length, int amplitude_in)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	dst.create(src.size(), src.type());
	Mat output = dst.getMat();

	int width = input.cols;
	int height = input.rows;

	float centreX = center.x * 1.0 / width; //0.25;
	float centreY = center.y * 1.0  / height; //0.5;
	//float radius = 90;

	if (radius==0)
		radius = std::min(width, height) / 2;

	int wavelength = (wave_length == 0) ?  radius / 2 : wave_length; //50;
	int amplitude = (amplitude_in == 0) ? wavelength / 4 : amplitude_in; //20

	if ( phases <= 2) phases = 4;
	float phase = M_PI / phases; // default = M_PI / 4;

	float icentreX=width*centreX;
	float icentreY=height*centreY;
	float radius2=radius*radius;

	float dx,dy,new_x,new_y;
	float p,q,x1,y1; //,x0,y0;
	float distance, distance2;
	float amount;

	for (int y=0; y<height; y++)
	{
		for (int x=0; x<width; x++)
		{

			 dx = x-icentreX;
			 dy = y-icentreY;

			 distance2=dx*dx+dy*dy;

			 if (distance2>radius2)
			 {
				 new_x=x;
				 new_y=y;
			 }
			 else
			 {
				 distance=sqrt(distance2);
				 amount=amplitude * sin(distance / wavelength * 2*M_PI - phase);
				 amount =amount* (radius-distance)/radius;
				 amount=amount*wavelength/(distance+0.0001);

				 new_x =x + dx*amount;
				 new_y =y + dy*amount;
			 }

			if(new_x<0)         new_x=0;
			if(new_x>=width-1)  new_x=width-2;
			if(new_y<0)         new_y=0;
			if(new_y>=height-1) new_y=height-2;

			x1=(int)new_x;
			y1=(int)new_y;

			p=new_x-x1;
			q=new_y-y1;

			for (int k=0; k<3; k++)
			{
				output.at<Vec3b>(y, x)[k]=(1-p)*(1-q)*input.at<Vec3b>(y1, x1)[k]+
										(p)*(1-q)*input.at<Vec3b>(y1,x1+1)[k]+
										(1-p)*(q)*input.at<Vec3b>(y1+1,x1)[k]+
										(p)*(q)*input.at<Vec3b>(y1+1,x1+1)[k];
			}

		}
	}
	return 0;
}

int  Filter::Pinch(InputArray src, OutputArray dst, float amount, Point center, float radiusPercent)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	dst.create(src.size(), src.type());
	Mat output = dst.getMat();


	int width = input.cols;
	int height = input.rows;

	float angle = M_PI / 2;
	float centreX = 0.5;
	float centreY = 0.5;

	float radius = std::min(width, height) * radiusPercent ;
	//float amount = 0.5;
	std::cout << amount << std::endl;

	if (radius==0)
		radius = std::min(width, height) / 2;

	float icentreX = width * centreX;
	float icentreY = height * centreY;

	if (center.x != 0 || center.y != 0) {
		icentreX = center.x;
		icentreY = center.y;
	}

	float radius2 = radius * radius;

	float dx, dy, new_x, new_y;
	float p, q, x1 ,y1;
	float distance;
	float a, d, t, s, c, e;

	for (int y = 0; y < height; ++y)
	{
		for (int x = 0; x < width; ++x)
		{
			 dx = x - icentreX;
			 dy = y - icentreY;

			 distance = dx*dx + dy*dy;

			 if (distance > radius2 || distance == 0)
			 {
				 new_x = x;
				 new_y = y;
			 }
			 else
			 {
				d  =  sqrt( distance / radius2 );
				t  =  pow( sin( M_PI * 0.5 * d ), -amount );

				dx  = dx* t;
				dy  = dy* t;

				e = 1 - d;
				a = angle * e * e;

				s = sin( a );
				c = cos( a );

				new_x = icentreX + c*dx - s*dy;
				new_y = icentreY + s*dx + c*dy;
			 }

			if(new_x<0)         new_x = 0;
			if(new_x>=width-1)  new_x = width - 2;
			if(new_y<0)         new_y = 0;
			if(new_y>=height-1) new_y = height - 2;

			x1=(int)new_x;
			y1=(int)new_y;

			p = new_x - x1;
			q = new_y - y1;

			for (int k = 0; k < 3; k++)
			{
				output.at<Vec3b>(y, x)[k]=(1-p)*(1-q)*input.at<Vec3b>(y1, x1)[k]+
										(p)*(1-q)*input.at<Vec3b>(y1,x1+1)[k]+
										(1-p)*(q)*input.at<Vec3b>(y1+1,x1)[k]+
										(p)*(q)*input.at<Vec3b>(y1+1,x1+1)[k];
			}

		}
	}
	return 0;
}


static float Triangle(float x)
{
    float temp_r = fmod(x, 1.0);

    if (temp_r < 0.5) {
       return 2 * temp_r;
    } else {
       return 2 * (1 - temp_r);
    }
}

int Filter::Kaleidoscope(InputArray src, OutputArray dst)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	dst.create(src.size(), src.type());
	Mat output = dst.getMat();

	//const uchar *in;
	//uchar *out;
	int width = input.cols;
	int height = input.rows;
	//int channels = input.channels();

	float angle = M_PI / 4;
	float angle2 = M_PI / 4;
	float centreX = 0.5;
	float centreY = 0.5;
	float sides = 4;

	float icentreX = width * centreX;
	float icentreY = height * centreY;
	float radius = 150;

	float dx, dy, new_x, new_y;
	float p, q, x1, y1;
	float c, r, theta, temp_theta, radius_c;

	for (int i = 0; i < height; ++i)
	{
		for (int j = 0; j < width; ++j)
		{
			 dx = j - icentreX;
			 dy = i - icentreY;

			 theta = atan2(dy, dx) - angle - angle2;
			 r = sqrt( dy * dy + dx * dx );

			 temp_theta = theta / M_PI * sides * 0.5;
			 theta = Triangle (temp_theta);

			 if (radius)
			 {
				c = cos(theta);
				radius_c = radius/c;
				r=radius_c * Triangle( r / radius_c );
			 }


			theta = theta + angle;

			new_x = r * cos(theta) + icentreX;
			new_y = r * sin(theta) + icentreY;

			if(new_x<0)         new_x = 0;
			if(new_x>=width-1)  new_x = width-2;
			if(new_y<0)         new_y = 0;
			if(new_y>=height-1) new_y = height-2;

//		    if (new_x < 0)     continue;
//		    if (new_x >= width-1)   continue;
//		    if (new_y >= height-1)  continue;
//		    if (new_y < 0)  continue;

			x1 = (int) new_x;
			y1 = (int) new_y;

			p = new_x - x1;
			q = new_y - y1;

			//in = input.ptr<uchar>(y1) + x1 * channels;;
			//out = output.ptr<uchar>(y) + x * channels;
			for (int k = 0; k < 3; ++k)
			{
				output.at<Vec3b>(i, j)[k]=
										COLOR_RANGE(
						                (1-p) * (1-q) * input.at<Vec3b>(y1, x1)[k] +
										(p) * (1-q) * input.at<Vec3b>(y1,x1+1)[k]+
										(1-p) * (q) * input.at<Vec3b>(y1+1,x1)[k]+
										(p) * (q)* input.at<Vec3b>(y1+1,x1+1)[k]
						                 );
			}

		}
	}
	return 0;
}



} /* namespace cv */

【完整演示代码下载】

https://download.csdn.net/download/FL1623863129/88600785

【参考文献】

1 https://blog.csdn.net/c80486/article/details/52506429

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2036805.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络编程】TCP机械臂测试

通过w(红色臂角度增大)s&#xff08;红色臂角度减小&#xff09;d&#xff08;蓝色臂角度增大&#xff09;a&#xff08;蓝色臂角度减小&#xff09;按键控制机械臂 注意&#xff1a;关闭计算机的杀毒软件&#xff0c;电脑管家&#xff0c;防火墙 1&#xff09;基于TCP服务器…

AFSim 仿真系统----《普朗克黑体辐射定律的区间积累》

参考文献 《普朗克黑体辐射函数的积分》&#xff0c;W. K. Widger, Jr. 和 M. P. Woodall&#xff0c;发表在《美国气象学会公报》&#xff0c;第57卷&#xff0c;第10期&#xff0c;1976年10月&#xff0c;页码1217-1219 上述参考文献描述了一种在不依赖于需要大量迭代的数值…

Visual Studio Code 安装与 C/C++ 语言运行总结

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; Visual Studio Code&#xff08;简称 VS Code&#xff09;是由微软开发的一款轻量级、强大的代码编辑器&#xff0c;支持多种编程语言和开发框架。由于其丰富的插件生态系统和灵活的配置选项&#xff0c;VS…

gitlab实现CI/CD自动化部署

gitlab实现CI/CD自动化部署 项目根目录中新增gitlab-ci.yml在gitlab上查看gitlab-runner配置方法配置服务器环境推送代码&#xff0c;触发runner&#xff0c;实现自动构建和部署参考 gitlab支持通过配置CI/CD实现自动化部署我们的代码项目&#xff0c;主要核心就是配置gitlab-c…

【MySQL数据库】单机、集群、分布式的区别

单机、集群和分布式是计算机系统中三种不同的架构模型,它们在资源管理、任务执行和性能优化方面有显著区别。 图片来源 1. 单机(Standalone) 单机指的是单一计算机系统,即所有的计算任务和数据都在一台计算机上处理。单机系统的特点包括: 硬件限制:受限于单台机器的计…

ARM处理架构中的PMU(Performance Monitoring Unit)和 AMU(Activity Monitors Unit)简介

在 ARM 架构中,PMU(Performance Monitoring Unit)和 AMU(Activity Monitors Unit)是用于性能分析和监控的硬件单元,但它们的功能和应用场景有所不同。以下是它们的主要区别: 1. PMU (Performance Monitoring Unit) 功能:PMU 是一种用于监控处理器性能的硬件单元。它可…

简述MYSQL聚簇索引、二级索引、索引下推

一丶聚簇索引 InnoDB的索引分为两种&#xff1a; 聚簇索引&#xff1a;一般创建表时的主键就会被mysql作为聚簇索引&#xff0c;如果没有主键则选择非空唯一索引作为聚簇索引&#xff0c;都没有则隐式创建一个索引作为聚簇索引&#xff1b;辅助索引&#xff1a;也就是非聚簇索…

Spring Web MVC入门(下)

1. 响应 1.1 返回静态页面 创建前端页面&#xff0c;如下图所示&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Index页面</title> </head> <body>Hello,Spring MVC…

利用栈去实现队列

利用栈实现队列 今天我们利用两个栈去实现队列&#xff08;因为是用c去实现队列没有c中的库函数所以我们要先手搓一个栈再去使用&#xff09; 没有实现的去看我的这篇文章&#xff1a;利用顺序表对栈的实现-CSDN博客 回顾一下特性&#xff1a;栈----先进后出、后进先出&…

我常用的几个傻瓜式爬虫工具,收藏!

爬虫类工具主要两种&#xff0c;一种是编程语言第三方库&#xff0c;比如Python的scrapy、selenium等&#xff0c;需要有一定的代码基础&#xff0c;一种是图形化的web或桌面应用&#xff0c;比如Web Scraper、后羿采集器、八爪鱼采集器、WebHarvy等&#xff0c;接近于傻瓜式操…

汇量科技Mintegral发布全新产品矩阵:助力广告主高效增长与变现

近期&#xff0c;汇量科技旗下程序化互动式广告平台Mintegral正式推出全新产品命名&#xff0c;期望通过简洁明确的产品名称&#xff0c;更好地传达Mintegral的品牌理念&#xff0c;使客户与平台的每一次接触都更加直接高效。 Mintegral AppGrowth(原Mintegral Self-Service Pl…

【idea】 已经commit还没push怎么修改commit信息?

前言&#xff1a; 有时候填写commit信息时手快确认了&#xff0c;要push时发现信息有误&#xff0c;此时想重新更改信息。 此方法适用于在idea里commit了的&#xff0c;且还未push。 &#xff08;u1s1&#xff0c;用idea来推送真的又快又方便&#xff0c;自此之后再也没碰过小乌…

Leetcode面试经典150题-112.路径总和

解法都在代码里&#xff0c;不懂就留言或者私信 超级简单的题&#xff0c;不过有隐形的坑 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.v…

算法定制与双光谱技术融合:提升巡检车入侵检测系统效能

一、应用背景 在当今数字化和信息化时代&#xff0c;算法已经成为企业提高效率、优化决策的重要工具。随着大数据、人工智能技术的迅速发展&#xff0c;客户对算法的需求呈现出爆发式增长。这种需求不仅体现在数量上&#xff0c;更体现在质量上&#xff0c;尤其是对算法定制化…

Dav_笔记13:SQL Access Advisor 之 1 Summary

SQL Access Advisor概述 SAA Summary 在调整数据库以实现复杂的数据密集型查询的最佳性能时&#xff0c;物化视图&#xff0c;分区和索引是必不可少的。 SQL Access Advisor通过为给定工作负载推荐适当的物化视图集&#xff0c;物化视图日志&#xff0c;分区和索引&#xff0c;…

macOS Sequoia 15 beta 5 (24A5309e) Boot ISO 原版可引导镜像下载

macOS Sequoia 15 beta 5 (24A5309e) Boot ISO 原版可引导镜像下载 iPhone 镜像、Safari 浏览器重大更新、备受瞩目的游戏和 Apple Intelligence 等众多全新功能令 Mac 使用体验再升级 请访问原文链接&#xff1a;https://sysin.org/blog/macOS-Sequoia-boot-iso/&#xff0c…

基于JAVA的外来人口管理系统设计与实现,源码、部署+讲解

摘 要 在新型冠状病毒性肺炎流行的背景下&#xff0c;我国数亿流动人口应该受到高度关注和保护。并让这一易感染人群离开成为“受害者传染源”的双重风险&#xff0c;的确是一项关键而富有挑战性的任务。因此&#xff0c;本毕业设计是以规模复杂的外来人口及居民群体为典例&am…

UI-无限循环列表

无限循环列表 创建 在任意节点上&#xff0c;添加Scroller&#xff0c;ScrollView组件&#xff0c;和RectMask2D组件&#xff1a; 其中列表的大小&#xff0c;依赖Rect的大小。 界面参数介绍 ViewPort&#xff1a;视口大小 SrollDirction:滚动方向 MovementType&#xff1a…

go语言后端开发学习(五)——如何在项目中使用Viper来配置环境

前言 在之前的文章中我们就介绍过用go-ini来读取配置文件,但是当时我们在介绍时说了他只能读取.ini格式的配置文件所以局限性较大,这里我们介绍一个适用范围更大的配置管理第三方库——Viper。 什么是Viper Viper是适用于Go应用程序&#xff08;包括Twelve-Factor App&#…

算法-差分, 二维前缀和, 离散化

文章目录 本节提要1. 一维差分1.1 一维差分原理分析1.2 一维差分例题应用 2. 等差数列差分2.1 等差数列差分原理分析 3. 二维前缀和3.1 二维前缀和原理分析3.2 二维前缀和例题应用 本节提要 本节的主要目标是一维差分的总结, 包括一维差分, 一维等差数列差分; 二维差分和二维前…