[C++][opencv]基于opencv实现photoshop算法可选颜色调整

【测试环境】

vs2019

opencv==4.8.0

【效果演示】

【核心实现代码】

SelectiveColor.hpp

#ifndef OPENCV2_PS_SELECTIVECOLOR_HPP_
#define OPENCV2_PS_SELECTIVECOLOR_HPP_#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;namespace cv {typedef enum select_color {SELECT_RED,SELECT_YELLOW,SELECT_GREEN,SELECT_CYAN,SELECT_BLUE,SELECT_MAGENTA,SELECT_WHITE,SELECT_MIDDLE,SELECT_BLACK
}  select_color_t;/*** Class of Adjustment for One Select Color*/
class SelectiveColorAdjust{
public:float cyan;       //青色调整值,取值范围: [-1, 1]float magenta;    //取值范围: [-1, 1]float yellow;     //取值范围: [-1, 1]float black;      //取值范围: [-1, 1]bool  defined;SelectiveColorAdjust();virtual ~SelectiveColorAdjust();void   calcDefined();
};/*** Class of Selective Color*/
class SelectiveColor {
public:bool isAbsolute;  //是否采用绝对方法SelectiveColorAdjust colors[ SELECT_BLACK + 1 ]; //9种可选颜色通道SelectiveColor();virtual ~SelectiveColor();int adjust(InputArray src, OutputArray dst); //实施可选颜色调整
};} /* namespace cv */#endif /* OPENCV2_PS_SELECTIVECOLOR_HPP_ */

 SelectiveColor.cpp


#include "SelectiveColor.hpp"#define DEBUG#ifndef DEBUG#define DEBUG_PRINT(a)
#define PRINT_VAR(var)
#define PRINT_VAR1(var)
#define PRINT_VARF(var)#else#include <iostream>
using namespace std;
#define DEBUG_PRINT(a)  cout << (a) << endl
#define PRINT_VAR(var)  cout << #var << " = " << (var) <<  endl
#define PRINT_VAR1(var) if ( nn == 0 ) cout << #var << " = " << int(var) <<  endl
#define PRINT_VARF(var) if ( nn == 0 ) cout << #var << " = " << double(var) <<  endl#endif#define SWAP(a, b, t)  do { t = a; a = b; b = t; } while(0)
#define CLIP_RANGE(value, min, max)  ( (value) > (max) ? (max) : (((value) < (min)) ? (min) : (value)) )
#define COLOR_RANGE(value)  CLIP_RANGE(value, 0, 255)#define MAX2(a, b) ( (a) > (b) ) ?  (a) : (b)
#define MAX3(a,b,c) ( ( a > b ) ?  MAX2(a,c) : MAX2(b,c) )
#define BLUE  0
#define GREEN 1
#define RED   2namespace cv {SelectiveColorAdjust:: SelectiveColorAdjust()
{cyan = 1.0;magenta = 1.0;yellow = 1.0;black = 1.0;defined = false;
}SelectiveColorAdjust::~SelectiveColorAdjust()
{}void SelectiveColorAdjust::calcDefined()
{if (cyan != 1.0 || magenta != 1.0 || yellow != 1.0 || black != 1.0 ) {defined =  true;return;}defined = false;
}//=========================================================
// SelectiveColorSelectiveColor::SelectiveColor() {isAbsolute = false;
}SelectiveColor::~SelectiveColor() {
}int SelectiveColor::adjust(InputArray src, OutputArray dst)
{Mat input = src.getMat();if( input.empty() ) {return -1;}dst.create(src.size(), src.type());Mat output = dst.getMat();//calculate color adjustment is definedfor(int i = 0; i < 9; i++ ) {colors[i].calcDefined();}const uchar *in;uchar *out;int width = input.cols;int height = input.rows;int channels = input.channels();int nn = 0;uchar t;  //tempuchar sorted[3];      //RGB value sorteduchar c[SELECT_BLACK + 1];float delta[3];  //delta of RGB valuefloat ratio[3],  ratio_positive[3], ratio_negative[3];for (int h = 0; h < height; h ++, nn++) {in = input.ptr<uchar>(h);  //pointer to input image dataout = output.ptr<uchar>(h); //pointer to output image datafor (int w = 0; w < width; w ++) {//Sort RGB values:  sorted[0] is biggest, sorted[1] is middle, sorted[2] is smallestmemcpy(sorted, in, 3);if (sorted[1] > sorted[0]) SWAP(sorted[0], sorted[1], t);if (sorted[2] > sorted[1]) SWAP(sorted[1], sorted[2], t);if (sorted[1] > sorted[0]) SWAP(sorted[0], sorted[1], t);//calculation c[] arraymemset(c, sizeof(c), 0);c[SELECT_BLUE] = in[BLUE];c[SELECT_GREEN] = in[GREEN];c[SELECT_RED] = in[RED];//subtract the smallest value from the RGBc[SELECT_BLUE]  -= sorted[2];c[SELECT_GREEN] -= sorted[2];c[SELECT_RED]   -= sorted[2];//calculate WHIT, MIDDLE, BLACKif ( sorted[2] <= 127 ) {c[SELECT_WHITE] = 0;c[SELECT_MIDDLE] = sorted[2] * 2;c[SELECT_BLACK]  = 255 - sorted[2] * 2;} else  {c[SELECT_WHITE]  = sorted[2] * 2 - 255;c[SELECT_MIDDLE] = 255 - (  sorted[2] - 127.5 ) * 2;c[SELECT_BLACK] = 0;}//calculate YELLOWif ( c[SELECT_RED] > 0 && c[SELECT_GREEN] > 0 ) {c[SELECT_YELLOW] = ( c[SELECT_RED] > c[SELECT_GREEN] ) ?  c[SELECT_GREEN] : c[SELECT_RED];c[SELECT_GREEN] -= c[SELECT_YELLOW];c[SELECT_RED]   -= c[SELECT_YELLOW];};//calculate CYANif ( c[SELECT_BLUE] > 0 && c[SELECT_GREEN] > 0 ) {c[SELECT_CYAN] = ( c[SELECT_BLUE] > c[SELECT_GREEN] ) ?  c[SELECT_GREEN] : c[SELECT_BLUE];c[SELECT_GREEN] -= c[SELECT_CYAN];c[SELECT_BLUE]  -= c[SELECT_CYAN];};//calculate MAGENTAif ( c[SELECT_BLUE] > 0 && c[SELECT_RED] > 0 ) {c[SELECT_MAGENTA] = ( c[SELECT_BLUE] > c[SELECT_RED] ) ?  c[SELECT_RED] : c[SELECT_BLUE];c[SELECT_RED]   -= c[SELECT_MAGENTA];c[SELECT_BLUE]  -= c[SELECT_MAGENTA];};//initialize delta[]delta[BLUE] = delta[GREEN] = delta[RED] = 0;//initialize ratiosfor(int i = 0; i < 3 ; i++ ) {ratio_positive[i] = in[i] / 255.0;ratio_negative[i] = ratio_positive[i] - 1 ;}//calculate each selective colorfor (int j = 0; j <= SELECT_BLACK; j++ ) {if ( colors[j].defined && (c[j] > 0) ) {if ( isAbsolute ) {ratio[RED] = colors[j].cyan + colors[j].black;ratio[RED] = CLIP_RANGE(ratio[RED], ratio_negative[RED], ratio_positive[RED]);ratio[GREEN] = colors[j].magenta + colors[j].black;ratio[GREEN] = CLIP_RANGE(ratio[GREEN], ratio_negative[GREEN], ratio_positive[GREEN]);ratio[BLUE] = colors[j].yellow + colors[j].black;ratio[BLUE] = CLIP_RANGE(ratio[BLUE], ratio_negative[BLUE], ratio_positive[BLUE]);} else {ratio[RED] = colors[j].cyan + ::abs(colors[j].cyan + 1) * colors[j].black;ratio[RED] = CLIP_RANGE(ratio[RED], -1, 1);ratio[RED] = ( ratio[RED] > 0 ) ? ratio[RED] * ratio_positive[RED] : - ratio[RED] * ratio_negative[RED];ratio[GREEN] = colors[j].magenta + ::abs(colors[j].magenta + 1) * colors[j].black;ratio[GREEN] = CLIP_RANGE(ratio[GREEN], -1, 1);ratio[GREEN] = ( ratio[GREEN] > 0 ) ? ratio[GREEN] * ratio_positive[GREEN] : - ratio[GREEN] * ratio_negative[GREEN];ratio[BLUE] = colors[j].yellow + ::abs(colors[j].yellow + 1) * colors[j].black;ratio[BLUE] = CLIP_RANGE(ratio[BLUE], -1, 1);ratio[BLUE] = ( ratio[BLUE] > 0 ) ? ratio[BLUE] * ratio_positive[BLUE] : - ratio[BLUE] * ratio_negative[BLUE];}delta[RED] -=  c[j] * ratio[RED];delta[GREEN] -=  c[j] * ratio[GREEN];delta[BLUE] -=  c[j] * ratio[BLUE];}}//save to outputout[BLUE]  = COLOR_RANGE( in[BLUE] + delta[BLUE] );out[GREEN] = COLOR_RANGE( in[GREEN] + delta[GREEN] );out[RED]   = COLOR_RANGE( in[RED] + delta[RED] );//move pointer forwardin += 3;out += 3;for (int j = 0; j < channels - 3; j++) {*out++ = *in++;}}}return 0;
}} /* namespace cv */

【完整演示代码下载地址】

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mariadb数据库本机无密码登录的问题解决

Mariadb数据库本机无密码登录的问题解决 安装了mariadb后&#xff0c;发现Mariadb本机无密码才能登录 百度了很多文章&#xff0c;发现很多人是因为root的plugin设置的值不正确导致的&#xff0c;unix_socket可以不需要密码&#xff0c;mysql_native_password 是正常的。 解…

NLP_情感分类_预训练加微调方案

文章目录 项目背景代码导包一些模型以及训练的参数设置定义dataset定义模型读取数据声明训练及测试数据集将定义模型实例化打印模型结构模型训练测试集效果 同类型项目 项目背景 项目的目的&#xff0c;是为了对情感评论数据集进行预测打标。在训练之前&#xff0c;需要对数据…

Datawhale X 魔搭 AI夏令营 第四期魔搭-AIGC文生图方向Task2笔记

了解一下 AI生图技术 的能力&局限 对所有人来说&#xff0c;定期关注AI生图的最新能力情况都十分重要&#xff1a; 对于普通人来说&#xff0c;可以避免被常见的AI生图场景欺骗&#xff0c;偶尔也可以通过相关工具绘图 对于创作者来说&#xff0c;通过AI生图的工具可以快速…

全球 30 万台游戏服务器的 PlayFlow Cloud 如何通过 DigitalOcean 实现动态扩展

“我在 DigitalOcean 上首次接触了 Kubernetes。设置 Kubernetes 集群非常简单&#xff0c;使我能够轻松自动化扩展我们的游戏服务器。”——Haseeb Sheikh&#xff0c;PlayFlow Cloud 创始人兼首席执行官 PlayFlow Cloud 是由 Haseeb Sheikh 创立的&#xff0c;旨在通过简化游…

13 Listbox 组件

13 Listbox 组件 Tkinter 的 Listbox 组件是一个用于显示列表项的控件&#xff0c;用户可以从中选择一个或多个项目。以下是对 Listbox 组件的详细说明和一个使用案例。 Listbox 组件属性 基本属性 width: 控件的宽度&#xff0c;通常以字符数为单位。height: 控件的高度&a…

Docker 网络代理配置及防火墙设置指南

Docker 网络代理配置及防火墙设置指南 背景 在某些环境中&#xff0c;服务器无法直接访问外网&#xff0c;需要通过网络代理进行连接。虽然我们通常会在 /etc/environment 或 /etc/profile 等系统配置文件中直接配置代理&#xff0c;但 Docker 命令无法使用这些配置。例如&am…

Midjourney提示词——《环太平洋》机甲专场(附公式)

前言 本篇为大家带来《环太平洋》的机甲提示词&#xff0c;文末附公式&#xff0c;有需要的可以直接复制点击下方阅读原文尝试使用哦~ 1、危险流浪者 Gypsy Danger, standing tall and heroic, dramatic lighting highlighting the metal plates, deep blue and silver color…

[图解]需要≠需求-《分析模式》漫谈

1 00:00:00,760 --> 00:00:02,910 今天的《分析模式》漫谈 2 00:00:02,920 --> 00:00:04,180 我们来说一下 3 00:00:04,490 --> 00:00:06,490 需要不等于需求 4 00:00:10,490 --> 00:00:11,760 还是第一章 5 00:00:13,120 --> 00:00:15,020 这里 6 00:00:1…

双胞胎命名有哪些特别之处?如何体现两者之间的联系与区别?

双胞胎命名艺术探秘 问题&#xff1a; 双胞胎命名有哪些特别之处&#xff1f;如何体现两者之间的联系与区别&#xff1f; 起尔网-免费取名|大师起名|宝宝起名|新生儿取名|男孩女孩在线起名姓名测试评分网起尔网-免费在线宝宝起名|新生儿取名|男孩女孩在线起名网&#xff0c;龙…

数据结构(学习)2024.8.6(顺序表)

今天开始学习数据结构的相关知识&#xff0c;大概分为了解数据结构、算法&#xff1b;学习线性表&#xff1a;顺序表、链表、栈、队列的相关知识和树&#xff1a;二叉树、遍历、创建&#xff0c;查询方法、排序方式等。 目录 一、数据结构 数据 逻辑结构 1.线性结构 2.树…

Ubuntu20.04 源码安装 OMPL 与 Moveit

文章目录 一、源码安装OMPL1.1 先检查是否已安装二进制 ompl1.2 若已经提前安装二进制&#xff0c;需先行卸载1.3 OMPL官网安装教程 二、源码安装 moveit2.1 先检查是否已安装二进制Moveit2.2 源码安装 Moveit2.2.1、更新软件包2.2.2、安装依赖2.2.3、创建Moveit工作空间2.2.4…

<Qt> 系统 - 文件

目录 一、Qt文件概述 二、输入输出设备类 三、文件读写类 四、文件和目录信息类 一、Qt文件概述 文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库&#xff0c;提供了跨平台的文件操作能力。Qt 提供了很多关于文件的类&#xff0c;通过这些类能够对文件系统进行操…

Openlayers6 图形绘制和修改功能(结合React)

Openlayers常用的API了解的差不多了&#xff0c;就开始进入实战了&#xff0c;首先从绘制基本的图形开始&#xff0c;这里主要介绍一下绘制圆形、矩形和多边形。 通过使用openlayers的ol.interaction.Draw和ol.interaction.Modify模块实现地图上绘制圆形、矩形、多边形并修改编…

mesh格式转换:glb转ply——使用Blender烘焙贴图到顶点色

1. 导入glb文件 选择shading后&#xff0c;选中物体&#xff0c;就能看到下面的节点树。 2. 创建顶点颜色 这个时候我们可以看到模型的顶点颜色是纯白色的。 2. 将贴图付给材质 原来&#xff1a; 现在&#xff1a; 3. 切换渲染器并烘焙顶点颜色 第三行选择CPU渲染或者GPU…

论文阅读:一种基于凸规划的高效有向最密子图发现方法 | SIGMOD 2022

论文概述 这篇论文的主题是研究如何在有向图中找到密度最高的子图&#xff0c;这个问题被称为有向最密子图&#xff08;Directed Densest Subgraph, DDS&#xff09;问题。该问题在许多应用中非常重要&#xff0c;如社交网络分析、社区发现、假粉丝检测等。论文提出了一种基于…

AI for reading ML paper

心流 心流 Kimi Kimi Humata Humata Bytez Bytez Chatgpt4 scholar 学术版chatgpt4&#xff0c;需要充值&#xff1b; 还有更多AI工具等待你发现&#xff1b;

sqlserver清理数据库日志并写作业定期执行

清理数据库日志最终sql&#xff1a; USE [master] GO ALTER DATABASE lsrz_zjwb_w SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE lsrz_zjwb_w SET RECOVERY SIMPLE --简单模式 GO USE lsrz_zjwb_w GO DBCC SHRINKFILE (Nlsrz_zjwb_log , 2, TRUNCATEONLY) --日志文件…

【网络】IO

IO 一、五种IO模型同步通信 vs 异步通信阻塞 vs 非阻塞 二、其他高级IO非阻塞IOSetNoBlockI/O多路转接之selectselect函数原型fd_set&#xff08;位图&#xff09;select代码select缺点poll&#xff08;用select修改&#xff09; I/O多路转接之epoll高级版改进select和poll的问…

企业如何组建安全稳定的跨国通信网络

当企业在海外设有分公司时&#xff0c;如何建立一个安全且稳定的跨国通信网络是一个关键问题。为了确保跨国通信的安全和稳定性&#xff0c;可以考虑以下几种方案。 首先&#xff0c;可以在分公司之间搭建虚拟专用网络。虚拟专用网络通过对传输数据进行加密&#xff0c;保护通信…

前端vue项目——打包部署(nginx中部署静态资源)

1、当前的开发方式 前端人员开发前端&#xff0c;后端人员开发后端的java工程&#xff0c;最终要将开发完毕的前端工程和后端工程分开部署在对应的服务器上&#xff08;前端流行的nginx&#xff09; 2、打包 &#xff08;1&#xff09;原理 &#xff08;2&#xff09; &#xf…