C++图像处理 -- 图像色阶调整
原网址:http://blog.csdn.net/maozefa/article/details/43971063
阅读提示:
《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。
《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。
尽可能保持二者内容一致,可相互对照。
本文代码必须包括《C++图像处理 -- 数据类型及公用函数》文章中的BmpData.h头文件。
在Photoshop中,图像色阶调整应用很广泛,本文介绍的图像色阶调整过程与Photoshop处理效果基本一致。
Photoshop的色阶调整分输入色阶调整和输出色阶调整,其中输入色阶调整有3个调整点,即通常所说的黑场、白场及灰场调整。
输入色阶调整的基本算法并不复杂,首先计算出白场与黑场的离差Diff,然后计算出像素各份量值与黑场的离差rgbDiff,如果rgbDiff<=0,像素各份量值等于0,否则,计算以rgbDiff与Diff的比值为底的灰场倒数的幂。用公式表示:
Diff = Highlight -Shadow
rgbDiff = RGB - Shadow
clRGB = Power(rgbDiff / Diff, 1 / Midtones)
其中Shadow为输入色阶低端数据(黑场),Highlight为输入色阶高端数据(白场), Midtones为输入色阶中间数据(灰场),Diff为二者的离差(必须大于1),RGB为调整前的像素分量值,clRGB为调整输入色阶后的像素分量值。
输出色阶调整更简单,首先计算输出色阶白场与黑场的离差与255的比值系数,然后用输入色阶调整后的像素分量值乘上这个系数,再加上输出黑场值即可。用公式表示:
outClRGB = clRGB * (outHighlight - outShadow) / 255 + outShadow
其中,outShadow为输出黑场,outHighlight为输出白场,outClRGB为全部色阶调整后的像素分量值。
前面已经提到输入色阶黑白场的离差必须大于1,而输入色阶并没有这个限制,输出黑白场的离差可以为负数,当输出黑场与白场完全颠倒时,输出色阶调整后的图片为原图片的负片。
色阶调整涉及四个通道,即R、G、B各分量通道及整体颜色通道,如果每个通道单独调整,将是比较麻烦和耗时的,本文采用色阶表替换法,可一次性完成所有四个通道的色阶调整。
下面是图像色阶调整的代码:
- // 色阶项结构
- typedef struct
- {
- UINT Shadow;
- FLOAT Midtones;
- UINT Highlight;
- UINT OutShadow;
- UINT OutHighlight;
- }ColorLevelItem, *PColorLevelItem;
- typedef struct
- {
- ColorLevelItem Blue;
- ColorLevelItem Green;
- ColorLevelItem Red;
- ColorLevelItem RGB;
- }ColorLevelData, *PColorLevelData;
- VOID InitColorLevelData(PColorLevelData clData)
- {
- PColorLevelItem item = &clData->Blue;
- for (INT i = 0; i < 4; i ++, item ++)
- {
- item->Shadow = item->OutShadow = 0;
- item->Highlight = item->OutHighlight = 255;
- item->Midtones = 1.0;
- }
- }
- BOOL GetColorLevelTable(PColorLevelItem item, LPBYTE clTable)
- {
- INT diff = (INT)(item->Highlight - item->Shadow);
- INT outDiff = (INT)(item->OutHighlight - item->OutShadow);
- if (!((item->Highlight <= 255 && diff < 255 && diff >= 2) ||
- (item->OutShadow <= 255 && item->OutHighlight <= 255 && outDiff < 255) ||
- (!(item->Midtones > 9.99 && item->Midtones > 0.1) && item->Midtones != 1.0)))
- return FALSE;
- DOUBLE coef = 255.0 / diff;
- DOUBLE outCoef = outDiff / 255.0;
- DOUBLE exponent = 1.0 / item->Midtones;
- for (INT i = 0; i < 256; i ++)
- {
- INT v;
- // 计算输入色阶黑白场
- if (clTable[i] <= (BYTE)item->Shadow)
- v = 0;
- else
- {
- v = (INT)((clTable[i] - item->Shadow) * coef + 0.5);
- if (v > 255)
- v = 255;
- }
- // 计算输入色阶灰场
- v = (INT)(pow(v / 255.0, exponent) * 255.0 + 0.5);
- // 计算输出色阶
- clTable[i] = (BYTE)(v * outCoef + item->OutShadow + 0.5);
- }
- return TRUE;
- }
- BOOL CheckColorLevelData(PColorLevelData clData, BYTE clTables[][256])
- {
- BOOL result = FALSE;
- INT i, j;
- for (i = 0; i < 3; i ++)
- {
- for (j = 0; j < 256; j ++)
- clTables[i][j] = (BYTE)j;
- }
- PColorLevelItem item = &clData->Blue;
- for (i = 0; i < 3; i ++, item ++)
- {
- if (GetColorLevelTable(item, clTables[i]))
- result = TRUE;
- }
- for (i = 0; i < 3; i ++)
- {
- if (!GetColorLevelTable(item, clTables[i]))
- break;
- result = TRUE;
- }
- return result;
- }
- // 图像数据色阶调整
- VOID ImageColorLevel(BitmapData *dest, BitmapData *source, PColorLevelData clData)
- {
- PARGBQuad pd, ps;
- UINT width, height;
- INT dstOffset, srcOffset;
- GetDataCopyParams(dest, source, width, height, pd, ps, dstOffset, srcOffset);
- BYTE clTables[3][256];
- if (CheckColorLevelData(clData, clTables))
- {
- for (UINT y = 0; y < height; y ++, ps += srcOffset, pd += dstOffset)
- {
- for (UINT x = 0; x < width; x ++, ps ++, pd ++)
- {
- pd->Blue = clTables[0][ps->Blue];
- pd->Green = clTables[1][ps->Green];
- pd->Red = clTables[2][ps->Red];
- pd->Alpha = ps->Alpha;
- }
- }
- }
- else if (dest != source)
- {
- for (UINT y = 0; y < height; y ++, ps += srcOffset, pd += dstOffset)
- {
- for (UINT x = 0; x < width; x ++, ps ++, pd ++)
- {
- pd->Color = ps->Color;
- }
- }
- }
- }
下面给一个简单的图像色阶调整函数调用例子:
- void __fastcall TForm1::Button1Click(TObject *Sender)
- {
- BitmapData dest, source;
- Bitmap *sBmp = new Bitmap(L"..\\..\\media\\source1.jpg");
- LockBitmap(sBmp, &source);
- Bitmap *dBmp = new Bitmap(source.Width, source.Height, PixelFormat32bppARGB);
- LockBitmap(dBmp, &dest);
- ColorLevelData clData;
- InitColorLevelData(&clData);
- clData.RGB.Shadow = 10;
- clData.RGB.Midtones = 1.2;
- clData.RGB.Highlight = 240;
- clData.RGB.OutShadow = 50;
- clData.RGB.OutHighlight = 200;
- /*
- clData.RGB.OutShadow = 255;
- clData.RGB.OutHighlight = 0;
- */
- ImageColorLevel(&dest, &source, &clData);
- UnlockBitmap(dBmp, &dest);
- UnlockBitmap(sBmp, &source);
- Gdiplus::Graphics g(Canvas->Handle);
- g.DrawImage(sBmp, 0, 0);
- g.DrawImage(dBmp, source.Width, 0);
- delete dBmp;
- delete sBmp;
- }
下面是文章《Delphi图像处理 -- 图像色阶调整》例子运行界面效果图,第一张效果图绿色通道色阶调整,第二张效果图是RGB输出色阶调整到完全颠倒时的负片图,详细的图像色阶调整界面例子请参考《Delphi图像处理 -- 图像色阶调整》。
本文代码系用BCB XE7编辑和编译。
因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com
这里可访问《C++图像处理 -- 文章索引》。
C++图像处理 -- 图像色阶调整相关推荐
- Photoshop图像处理算法—色阶调整
前言:之前在公司做项目的用到photoshop颜色空间的一些相关方法,在此总结一下.下面原理部分是从我的总结文档里截取来的.需要复制的童鞋自己手写一下~ 2.程序部分 1)Matlab实验程序. cl ...
- OpenCV—python 色阶调整(直方图均衡化 图像去雾)
文章目录 一.色阶调整( Levels Adjustment )原理 二.自动色阶图像处理算法 一.色阶调整( Levels Adjustment )原理 色阶:就是用直方图描述出的整张图片的明暗信息 ...
- Python+Opencv图像处理新手入门教程(二):颜色空间转换,图像大小调整,灰度直方图
一步一步来吧 上一节:Python+Opencv图像处理新手入门教程(一):介绍,安装与起步 1.什么是图像 对于计算机而言,图像的本质是一个由像素点构成的矩阵. 例如我们用肉眼很容易分辨一辆汽车的后 ...
- 计算机图像处理实验四:图像对比度调整(MATLAB)
[实验名称] 图像对比度调整 [实验目的] 通过本次实验掌握图像对比度自动调整技术: .熟悉使用库函数imhist.histeq: [实验内容] 利用库函数imhist计算并分别显示下图(图1)中图 ...
- 使用TensorFlow进行常用的图像处理-图像转为矩阵以及图像大小调整
图像编码处理 将图像转为一个三维矩阵,并使用三维矩阵形成一个图像: import tensorflow as tf import matplotlib.pyplot as plt# 读取原始图像数据 ...
- 【OpenCV 例程300篇】206. Photoshop 色阶调整算法
OpenCV 例程200篇 总目录 201. 图像的颜色空间转换 202. 查表快速替换(cv.LUT) 203. 伪彩色图像处理 204. 图像的色彩风格滤镜 205. 调节色彩平衡/饱和度/明度 ...
- 使用Julia进行图像处理--图像表示与匹配算法
使用Julia进行图像处理--图像表示与匹配算法 图像表示 特征和描述符 快速角点检测 使用imcorner函数进行角点检测 性能比较 BRIEF--有效检测重复图像的方法 识别图像重复项 使用多张图 ...
- python实现简单的ps色阶调整过程
最近在做一个用unet神经网络识别种子出苗率的项目(种子贼小,分辨率还贼低),由于识别的效果不太好,只能对图像做预处理了...预处理选用的是ps中的色阶处理,可是cv2等图像库中没有现成的函数,只能自 ...
- C++图像处理 -- 图像颜色混合(下)
阅读提示: <C++图像处理>系列以代码清晰,可读性为主,全部使用C++代码. <Delphi图像处理>系列以效率为侧重点,一般代码为PASCAL,核心代码采用 ...
最新文章
- comparator java_java:Comparator比较器
- OpenResty介绍
- CSS中盒模型的理解
- mysql 开发基础系列22 SQL Model(带迁移事项)
- linux mysql安装教程 方大帝_discuz论坛出现Can not connect to MySQL server错误的解决方法...
- .net宿舍管理系统 mysql_基于.NET CORE的精美后台管理系统-RuoYi C#版
- STM32工作笔记0030---编写跑马灯实验--使用库函数
- 分布式多副本一致性协议:paxos
- Atitit 代理与分销系统(1) 子代理 充值总额功能设计概览 sum() groubpy subagt
- 产业区块链一周动态丨数字货币发展写入十四五规划,湖南印发区块链发展规划...
- linux没有telnet命令
- Flutter跑马灯Marquee
- [黑马程序员C++笔记]P99-P104类和对象-封装
- idea的安装及基础设置
- python中的sort排序加换行_python中sort()排序的方法
- 海思NNIE开发(一):海思Hi3559AV100/Hi3519AV100 NNIE深度学习模块开发与调试记录
- java异常面试_java中异常的面试
- 下列实型常量不符合c语言,C语言程序设计考试题答案
- 第八次作业——Excel制作工资表
- python二进制方式读取文件,并将读取出的数据以txt的格式保存