[C++][opencv]基于opencv实现photoshop算法色阶调整

news2024/12/30 2:23:40

【测试环境】

vs2019

opencv==4.8.0

【效果演示】

【核心实现代码】

Levels.hpp

#ifndef OPENCV2_PS_LEVELS_HPP_
#define OPENCV2_PS_LEVELS_HPP_

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;

namespace cv {

/**
 * Class of Level for one channel
 */
class Level {
public:
	int   Shadow;  //输入色阶黑点值
	float Midtones; //输入色阶灰点值(注意是浮点数)
	int   Highlight; //输入色阶白点值

	int   OutputShadow; //输出色阶黑点值
	int   OutputHighlight; //输出色阶白点值

	Level();
	virtual ~Level();

	bool createColorTable(uchar * colorTable);
	void clear();
};

/**
 * Class of Levels for all channels
 */
class Levels {
protected:
	bool createColorTables(uchar colorTables[][256]);

public:
	Level RGBChannel;  //RGB整体调整
	Level RedChannel;  //红色通道
	Level GreenChannel; //绿色通道
	Level BlueChannel; //蓝色通道

	Levels();
	virtual ~Levels();

	int adjust(InputArray src, OutputArray dst); //实施色阶调整
};


} /* namespace cv */

#endif /* OPENCV2_PS_LEVELS_HPP_ */

 Levels.cpp

#include "Levels.hpp"

namespace cv {

Level::Level() {
	clear();
}

Level::~Level() {

}

void Level::clear() {
	Shadow = OutputShadow = 0;
	Highlight = OutputHighlight = 255;
	Midtones = 1.0;
}

//create color table for a channel
bool Level::createColorTable(uchar * colorTable)
{
    int diff = (int)(Highlight - Shadow);
    int outDiff = (int)(OutputHighlight - OutputShadow);

    if (!((Highlight <= 255 && diff <= 255 && diff >= 2) ||
        (OutputShadow <= 255 && OutputHighlight <= 255 && outDiff < 255) ||
        (!(Midtones > 9.99 && Midtones > 0.1) && Midtones != 1.0)))
        return false;

    double coef = 255.0 / diff;
    double outCoef = outDiff / 255.0;
    double exponent = 1.0 / Midtones;

    for (int i = 0; i < 256; i ++)
    {
        int v;
        // calculate black field and white field of input level
        if ( colorTable[i] <= (uchar)Shadow ) {
            v = 0;
        } else {
            v = (int)((colorTable[i] - Shadow) * coef + 0.5);
            if (v > 255) v = 255;
        }
        // calculate midtone field of input level
        v = (int)( pow(v / 255.0, exponent) * 255.0 + 0.5 );
        // calculate output level
        colorTable[i] = (uchar)( v * outCoef + OutputShadow + 0.5 );
    }

    return true;
}

//==================================================================
// Levels

Levels::Levels() {
}

Levels::~Levels() {

}

bool Levels::createColorTables(uchar colorTables[][256])
{
    bool result = false;
    int i, j;

    //initialize color table
    for (i = 0; i < 3; i ++) {
        for (j = 0; j < 256; j ++)
            colorTables[i][j] = (uchar)j;
    }

    //create color table for each channel
    result = BlueChannel.createColorTable( colorTables[0]);
    result = GreenChannel.createColorTable( colorTables[1]);
    result = RedChannel.createColorTable( colorTables[2]);

    result = RGBChannel.createColorTable( colorTables[0]);
    result = RGBChannel.createColorTable( colorTables[1]);
    result = RGBChannel.createColorTable( colorTables[2]);

    return result;
}


int Levels::adjust(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();

	uchar colorTables[3][256];

	//create color tables
	if ( ! createColorTables( colorTables ) )  {
		//error create color table"
		return 1;
	}

	//adjust each pixel
	#ifdef HAVE_OPENMP
	#pragma omp parallel for
	#endif
	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 c = 0; c < 3; c++) {
				*out++ = colorTables[c][*in++];
			}
			for (int c = 0; c < channels - 3; c++) {
				*out++ = *in++;
			}
		}
	}

	return 0;
}


} /* namespace cv */

【完整演示代码下载】

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

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

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

相关文章

Re:从零开始的逆向笔记02day

1-C语言 参数传递 参数传递是通过堆栈的&#xff0c;传递的顺序是从右到左 函数返回值是存储在寄存器eax中 类型 char x -1; //0xFF 1111 1111 int y x; //0xFFFFFFFF 1111 1111 1111 1111 1111 1111 1111 1111 其余位为符号位unsigned char x -1; //0xFF 1111 1111 in…

云快充协议1.5版本的充电桩系统软件

介绍 小程序端&#xff1a;城市切换、附近电站、电桩详情页、扫码充电、充电中动态展示、订单支付、个人中心、会员充值、充值赠送、联系客服&#xff1b; 管理后台&#xff1a;充电数据看板、会员管理、订单管理、充值管理、场站运营、文章管理、财务管理、意见反馈、管理员管…

腾讯云COS和阿里云OSS在Springboot中的使用

引言&#xff1a;之前本来是用OSS做存储的&#xff0c;但是上线小程序发现OSS貌似消费比COS多一些&#xff0c;所以之前做了技术搬迁&#xff0c;最近想起&#xff0c;打算做个笔记记录一下&#xff0c;这里省去在阿里云注册OSS或腾讯云中注册COS应用了。 一、OSS 1、配置yml …

Linux 网络设备驱动

一.网络设备驱动框架 接收 将报文从设备驱动接受并送入协议栈 老API netif_if 编写网络设备驱动 步骤 1.注册一个网络设备 2.填充net_device_ops结构体 3.编写接收发送函数 // SPDX-License-Identifier: GPL-2.0-only /** This module emits "Hello, world"…

IOS 02 SnapKit 纯代码开发

SnapKit是一个Swift语言写的自动布局框架&#xff0c;可以运行到iOS&#xff0c;Mac系统上&#xff1b;OC版本的框架是Masonry&#xff0c;都是出自同一个团队。 用这个框架的目的是&#xff0c;用起来比系统自带的API方便&#xff0c;他内部也是对系统API进行了封装。 为什么…

房产中介小程序

本文来自&#xff1a;ThinkPHPFastAdmin房产中介小程序 - 源码1688 应用介绍 产中介小程序是一款基于ThinkPHPFastAdmin开发的原生微信小程序&#xff0c;为房地产中介提供房源管理、发布、报备客户、跟踪客户以及营销推广获客等服务的系统。 前端演示&#xff1a; 后台演示&am…

HarmonyOS应用开发者基础认证(三)

1、针对包含文本元素的组件&#xff0c;例如Text、Button、TextInput等&#xff0c;可以使用下列哪些属性&#xff1a;&#xff08;全选&#xff09; 答案&#xff1a; fontColor fontFamily fontSize fontWeight fontStyle 分析&#xff1a; 2、关于Tabs组件和TabContent组件&…

【高效笔记与整理的艺术】

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

通过jmeter对websocket后台做压测

后台使用java程序&#xff0c;通过springboot集成的stomp协议暴露websocket接口&#xff0c;所以下文测试过程会有特定的stomp报文&#xff0c;无需在意&#xff0c;关注流程即可 本次测试使用jmeter模拟大量用户接收群消息的场景&#xff0c;可覆盖连接数以及消息并发的压测 一…

CentOS7.6 RabbitMQ消息队列集群部署——实施方案

1、前期环境准备&#xff08;每个主机都配置&#xff09; 1.准备三台主机 IP地址主机名内存大小192.168.200.10 rabbitmq1 2G192.168.200.11rabbitmq22G192.168.200.55rabbitmq32G 2. 设置主机名 hostnamectl set-hostname 主机名suexit Ctrlr 3. 设置IP地址然后重启网卡 …

深度学习与图像修复:ADetailer插件在Stable Diffusion中的应用

文章目录 引言ADetailer插件介绍插件安装常用模型控制提示词参数配置参数详解 实践建议 示例插件的对比&#xff1a;1. ADetailer插件2. Photoshop插件&#xff08;如Nik Collection&#xff09;3. GIMP插件&#xff08;如GMIC&#xff09;4. Affinity Photo插件 结语 引言 无…

【物联网】(蓝牙篇)微信小程序ios如何自动打开蓝牙

微信小程序打开蓝牙的便捷之道——微信小程序ios如何自动打开蓝牙 随着智能手机蓝牙技术和物联网产品的普及&#xff0c;很多人在使用微信小程序时&#xff0c;都希望能够更便捷地打开蓝牙功能。 在iOS系统上&#xff0c;由于其封闭性和权限控制严格&#xff0c;使得自动打开蓝…

OpenGL ES->GLSurfaceView进行点、线段、三角形等基本图元的绘制

GLSurfaceView代码见OpenGL ES-&#xff1e;顶点着色器和片段着色器代码&#xff0c;只修改顶点数组&#xff0c;片段着色器的颜色&#xff0c;和绘制方式进行不同图元绘制 绘制点 GL_POINTS方式 // 顶点数据 val vertices floatArrayOf(0.8f, -0.8f, 0.0f,-0.8f, -0.8f, 0…

Python大数据分析——SVM模型(支持向量机)

Python大数据分析——SVM模型&#xff08;支持向量机&#xff09; 认知模型介绍距离计算模型思想目标函数函数与几何间隔 线性可分SVM模型目标函数函数代码 非线性可分SVM模型目标函数函数代码 示例手写体字母识别森林火灾面积预测 认知模型 介绍 超平面的理解&#xff1a;在…

Stable Diffusion绘画 | 进阶语法

控制提示词生效时间 使用格式1&#xff1a;[提示词:0-1数值] 举例&#xff1a;forest,lots of trees and stones,[flowers:0.7] 其中 [flowers:0.7] 表示整体画面采样值达到70%的进程以后&#xff0c;才开始计算花的采样。 因此&#xff0c;花的数量仅仅只跑了末段的30%&am…

LeetCode之回溯

1.全排列 1.1 题目 1.2 题解 LeetCode 力扣官方题解 1.3 代码 class Solution {public List<List<Integer>> permute(int[] nums) {// 创建一个空的列表 res&#xff0c;用于存储所有的排列结果List<List<Integer>> res new ArrayList<>();/…

C++入门基础:数据类型与条件判断语句

数据类型 基础数据类型 整型&#xff08;Integral Types&#xff09; int&#xff1a;基本的整型&#xff0c;大小依赖于编译器和平台&#xff0c;通常是32位或64位。 short&#xff1a;短整型&#xff0c;通常是16位。 long&#xff1a;长整型&#xff0c;大小依赖于编译…

本地部署Code Llama大模型结合Text generation Web UI远程运行LLM

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

pdf拆分成一页一页,怎么操作?pdf拆分的好用方法

pdf拆分成一页一页&#xff0c;怎么操作&#xff1f;PDF文件的拆分通常涉及到以下几个常见场景和需求&#xff1a;首先&#xff0c;PDF文件可能包含大量的页面&#xff0c;例如数百页的电子书或详尽的技术手册。在某些情况下&#xff0c;用户可能只需要处理其中的几页或者想要单…

揭秘!亚马逊与速卖通自养号测评:必备资源与技术要点

面对测评服务商的种种承诺&#xff0c;其真实性往往难以验证&#xff0c;而在像Facebook这样的社交平台上自行寻找测评资源&#xff0c;也显得相当困难和不切实际。随着产品即将上架&#xff0c;寻找一个可靠的测评服务似乎并不那么容易。因此&#xff0c;对于亚马逊等跨境平台…