作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

实现原理

PS中的阴影命令是一种用于校正由强逆光而形成剪影的照片的方法。在用其他方式采光的图像中,这种调整也可用于使阴影区域变亮。要实现图像的阴影调整,首先要识别出阴影区;再通过对阴影区的色彩进行一定变换,使其达到提光或者暗化效果;最后也是最重要的,就是对阴影区和非阴影区的边缘作平滑处理。

下方介绍具体流程。

具体流程

1)读取识别图像的原图,并转灰度图,再归一化。

// 生成灰度图
cv::Mat gray = cv::Mat::zeros(input.size(), CV_32FC1);
cv::Mat f = input.clone();
f.convertTo(f, CV_32FC3);
vector<cv::Mat> pics;
split(f, pics);
gray = 0.299f*pics[2] + 0.587*pics[2] + 0.114*pics[0];
gray = gray / 255.f;

图1 灰度处理

2)确定阴影区。因为我们要识别阴影,所以thresh通过(1-gray)*(1-gray),得到的图像中原本暗的地方则为亮,取平均值当阈值,进行二值化得到掩膜mask。

// 确定阴影区
cv::Mat thresh = cv::Mat::zeros(gray.size(), gray.type());
thresh = (1.0f - gray).mul(1.0f - gray);
// 取平均值作为阈值
Scalar t = mean(thresh);
cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);
mask.setTo(255, thresh >= t[0]);

图2 阴影掩膜区

3)对掩膜区边缘进行平滑过渡。假设light为50,那么midrate的掩膜区值为1.5,黑色区为1,过渡区为1~1.5;bright的掩膜区为0.125,黑色区为0,过渡区为0~0.125。

// 参数设置
int max = 4;
float bright = light / 100.0f / max;
float mid = 1.0f + max * bright;// 边缘平滑过渡
cv::Mat midrate = cv::Mat::zeros(input.size(), CV_32FC1);
cv::Mat brightrate = cv::Mat::zeros(input.size(), CV_32FC1);
for (int i = 0; i < input.rows; ++i)
{uchar *m = mask.ptr<uchar>(i);float *th = thresh.ptr<float>(i);float *mi = midrate.ptr<float>(i);float *br = brightrate.ptr<float>(i);for (int j = 0; j < input.cols; ++j){if (m[j] == 255){mi[j] = mid;br[j] = bright;}else {mi[j] = (mid - 1.0f) / t[0] * th[j]+ 1.0f;   br[j] = (1.0f / t[0] * th[j])*bright;               }}
}

4)根据midrate和brightrate,进行阴影区提亮。对非阴影区而言,midrate都为1,brightrate都为0,即没有变化;对阴影区而言,midrate都为1.5,brightrate都为0.125,所以色彩数值均有所增加,带来了提亮效果;对边缘地区,midrate和brightrate起到了很好的过渡作用。

注意:temp要进行数值限制,假设temp大于1,则进行uchar处理后数值会因为类型原因产生突变,那么图像也就变成了五颜六色。

// 阴影提亮,获取结果图
cv::Mat result = cv::Mat::zeros(input.size(), input.type());
for (int i = 0; i < input.rows; ++i)
{float *mi = midrate.ptr<float>(i);float *br = brightrate.ptr<float>(i);uchar *in = input.ptr<uchar>(i);uchar *r = result.ptr<uchar>(i);for (int j = 0; j < input.cols; ++j){for (int k = 0; k < 3; ++k){float temp = pow(float(in[3 * j + k]) / 255.f, 1.0f / mi[j])*(1.0 / (1 - br[j]));if (temp > 1.0f)temp = 1.0f;if (temp < 0.0f)temp = 0.0f;uchar utemp = uchar(255*temp);r[3 * j + k] = utemp;}}
}

C++测试代码

#include <iostream>
#include <opencv2/opencv.hpp>using namespace std;
using namespace cv;cv::Mat Shadow(cv::Mat input, int light);int main()
{cv::Mat src = imread("test2.jpg");int light = 50;cv::Mat result = Shadow(src,light);imshow("original", src);imshow("result", result);waitKey(0);return 0;
}// 图像阴影选取
cv::Mat Shadow(cv::Mat input, int light)
{// 生成灰度图cv::Mat gray = cv::Mat::zeros(input.size(), CV_32FC1);cv::Mat f = input.clone();f.convertTo(f, CV_32FC3);vector<cv::Mat> pics;split(f, pics);gray = 0.299f*pics[2] + 0.587*pics[2] + 0.114*pics[0];gray = gray / 255.f;// 确定阴影区cv::Mat thresh = cv::Mat::zeros(gray.size(), gray.type()); thresh = (1.0f - gray).mul(1.0f - gray);// 取平均值作为阈值Scalar t = mean(thresh);cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);mask.setTo(255, thresh >= t[0]);// 参数设置int max = 4;float bright = light / 100.0f / max;float mid = 1.0f + max * bright;// 边缘平滑过渡cv::Mat midrate = cv::Mat::zeros(input.size(), CV_32FC1);cv::Mat brightrate = cv::Mat::zeros(input.size(), CV_32FC1);for (int i = 0; i < input.rows; ++i){uchar *m = mask.ptr<uchar>(i);float *th = thresh.ptr<float>(i);float *mi = midrate.ptr<float>(i);float *br = brightrate.ptr<float>(i);for (int j = 0; j < input.cols; ++j){if (m[j] == 255){mi[j] = mid;br[j] = bright;}else {mi[j] = (mid - 1.0f) / t[0] * th[j]+ 1.0f;   br[j] = (1.0f / t[0] * th[j])*bright;               }}}// 阴影提亮,获取结果图cv::Mat result = cv::Mat::zeros(input.size(), input.type());for (int i = 0; i < input.rows; ++i){float *mi = midrate.ptr<float>(i);float *br = brightrate.ptr<float>(i);uchar *in = input.ptr<uchar>(i);uchar *r = result.ptr<uchar>(i);for (int j = 0; j < input.cols; ++j){for (int k = 0; k < 3; ++k){float temp = pow(float(in[3 * j + k]) / 255.f, 1.0f / mi[j])*(1.0 / (1 - br[j]));if (temp > 1.0f)temp = 1.0f;if (temp < 0.0f)temp = 0.0f;uchar utemp = uchar(255*temp);r[3 * j + k] = utemp;}}}return result;
}

测试效果

图1 原图

图2  light为50的效果图

图3 light为-50的效果图

从测试效果中可以看出,阴影区随light变化而产生亮度变化,当light为正值时,阴影区有明显提亮效果;反之,则变更暗。

如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~

如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

OpenCV-图像阴影调整相关推荐

  1. opencv 图像阴影检测

    opencv 图像阴影检测  GarfieldEr007 2017-01-09  原文 参数说明: IplImage *workImg-当前全局变量,表示正在显示的图片. downleft, upri ...

  2. Python+Opencv图像处理新手入门教程(二):颜色空间转换,图像大小调整,灰度直方图

    一步一步来吧 上一节:Python+Opencv图像处理新手入门教程(一):介绍,安装与起步 1.什么是图像 对于计算机而言,图像的本质是一个由像素点构成的矩阵. 例如我们用肉眼很容易分辨一辆汽车的后 ...

  3. 基于opencv的图像阴影消除车辆变道检测

    基于opencv的图像阴影消除 详细代码在这!!! 最大滤波 def max_filtering(N, I_temp):wall = np.full((I_temp.shape[0]+(N//2)*2 ...

  4. Opencv图像的亮度和对比度调整

    文章目录 前言 一.图像亮度和对比度的基本概念: 1.图像亮度: 2.图像对比度: 二.RGB三通道色彩空间的图像变换: 1.线性变换公式如下: 2.操作简介: 3.图像亮度调整: 4.图像对比度调整 ...

  5. OpenCV图像梯度(Sobel和Scharr)

    OpenCV图像梯度(Sobel和Scharr) 1 图像梯度是什么? 2 图像梯度的用途 3 图像梯度的使用 参考 这篇博客将介绍图像渐变以及如何使用OpenCV的cv2.Sobel计算Sobel渐 ...

  6. OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔总结

    我们经常会将某种尺寸的图像转换为其他尺寸的图像,如果放大或者缩小图片的尺寸,笼统来说的话,可以使用OpenCV为我们提供的如下两种方式: <1> resize函数.这是最直接的方式, &l ...

  7. 发现你的身形——OpenCV图像轮廓

    文章目录 写在最前 轮廓发现算法 边缘检测 写在最后 写在最前 我的意思不是说你长得很胖,emmmm,而是你的轮廓很大. --五星上将詹姆斯下士如是说 果然有图没图,理解是不一样的,这就体现了计算机视 ...

  8. 转载:矩阵的掩膜操作实现图像对比度调整

    矩阵的掩膜操作实现图像对比度调整 hb707934728 2017-07-04 13:54:17 1170 收藏 最后发布:2017-07-04 13:54:17首发:2017-07-04 13:54 ...

  9. OpenCV图像仿射变换

    OpenCV图像的旋转是通过图像的仿射变换来实现的,实现图像的旋转,分为三个步骤: 第一步:确定旋转角度和旋转中心. 第二步:确定旋转矩阵.通过getRotationMatrix2D函数计算出. 第三 ...

最新文章

  1. Ember.js 入门指南——定义模型
  2. Leetcode: Intersection of Two Arrays
  3. 浅析:setsockopt()改善程序的健壮性【转】
  4. python的用途实例-python中类方法,实例方法,静态方法的作用和区别
  5. linux samba默认端口,Linux 指定端口挂载samba 亲测可用!
  6. Pandas库DataFrame的排序
  7. Matlab练习:timer(定时器)
  8. 数据结构之深度优先搜索(用栈实现)问题
  9. SpringCloud企业实战专栏
  10. 无法访问机械硬盘提示执行页内操作时的错误的文件恢复办法
  11. IE8浏览器跨域接口访问异常的解决办法
  12. 手机麦克风结构原理图_一文看懂咪头的工作原理及结构(驻极体话筒) - 全文...
  13. oracle使用sql循环语句,常用SQL/oracle循环语句
  14. 什么是卡诺图,如何用卡诺图表示逻辑函数,如何用卡诺图化简逻辑函数
  15. 招投标工作中投标书编制的流程是怎样的?
  16. 李白藏头诗鸿蒙,【表白的诗句藏头诗】表白的诗句60句
  17. 【ICPC-457】数学笔记
  18. 云智慧透视宝PHP应用性能监控实现原理
  19. 【高级微观经济学】利润最大化
  20. OkHttp3基本使用

热门文章

  1. NO32 网络层次及OSI7层模型--TCP三次握手四次断开--子网划分
  2. gitlab+jenkins+ansible集成持续发布
  3. Android之使用枚举利弊及替代方案
  4. Lenovo E47A Ubuntu闪屏解决办法
  5. oracle instr函数详解
  6. 寻找最大的K个数(下)
  7. server.xml解析
  8. Java技术专题之JVM逻辑内存回收机制研究图解版
  9. ubuntu 12.04 php升级,Ubuntu下如何升级到PHP7.4的方法步骤
  10. inventor如何钣金出弧面_Inventor技巧丨外螺纹内径尺寸计算原理