数字图像处理-对比度调整背景相减
数字图像处理-对比度调整&背景相减
实验题目: 实验E2:图像代数运算
实验2.1:对比度调整
实验过程中遇到和解决的问题:
对比度调整因为给的图片没有上课所说的细节,实验要求没有指出,这里存在问题如果图片细节较多,可能会细节缺失,通过亮度加以调整,sigmod函数的数学形式分析,关于像素范围与sigmod原函数范围的转化
sigmod函数:
F
(
x
)
=
1
1
+
e
−
x
F(x)=\frac{1}{1+e^{-x}}
F(x)=1+e−x1
将像素值转化到[-1,1], 然后通过系数进行缩放,系数越大,正值越大,负值越小,对应sigmod函数上的取值差异越大,表现为像素值大于127的更亮,小于127的更暗, 图像对比度增强,反之;
图像亮度是图像整体像素值的增大或者减小,这里直接在转化后图像像素值加一个值来控制亮度, 代码实现为:
double t = ((g_srcImage.at<Vec3b>(y, x)[c] - 127) / 225.00) * g_nContrastValue * 0.1;
g_dstImage.at<Vec3b>(y, x)[c] = saturate_cast<uchar>(g_srcImage.at<Vec3b>(y, x)[c] * ((1.00 / (1.00 + exp(-t))) + 0.5) + g_nBrightValue - 100);
数值溢出问题
通过saturate_cast来控制范围.
结果分析与体会:
增强对比度:
增强亮度:
- 可以看到对比度让明暗对比更明显; 亮度是整体变化.
更多实验:
实验2.2:背景相减
实验过程中遇到和解决的问题:
图像背景稍微有变动,产生噪声干扰。
通过上网了解到图像平滑,通过中值滤波,对图像边界特征还没有完全消失的时候,对背景做平滑处理;
cv::medianBlur(front_mask, new_front_mask, 3);
图像的亮度曝光度不同导致背景不能完全去除。
背景相减之后要通过一个阈值处理然后产生mask,可以解决明暗问题。
图像的一些边界不能显示。
阈值调整, 中值平滑, 暂时没有很好的解决思路.
核心代码:
cv::absdiff(image, image_bg, front_mask);
/* imshow("New Image", front_mask);
waitKey(0);*/
//通过每个通道的平方和最后开方设定阈值
for (int y = 0; y < image.rows; y++) {
for (int x = 0; x < image.cols; x++) {
int tsum = 0;
for (int c = 0; c < 3; c++) {
tsum += front_mask.at<Vec3b>(y, x)[c]* front_mask.at<Vec3b>(y, x)[c];
}
tsum = sqrt(tsum);
if (tsum < value) {
front_mask.at<Vec3b>(y, x)[0] = 0; front_mask.at<Vec3b>(y, x)[1] = 0; front_mask.at<Vec3b>(y, x)[2] = 0;
}
else {
front_mask.at<Vec3b>(y, x)[0] = 255; front_mask.at<Vec3b>(y, x)[1] = 255; front_mask.at<Vec3b>(y, x)[2] = 255;
}
}
}
结果分析与体会:
- 影子的背景干扰很难去除
- 通过中值滤波平滑得到对于背景的很多噪声做了处理;
- 裤子的阴影部分边界模糊
更多实验:
- 前景部分零件不能很好的抽离出来
- 可以针对特定场景限定, 比如针对分离后的图像做最大值滤波, 但没有普适性.
代码
brackground:
#include<opencv2/core/core.hpp>
#include<opencv2/imgcodecs.hpp>
#include<opencv2/core/saturate.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
#include <opencv2/imgproc.hpp>
#include<cmath>
using namespace std;
using namespace cv;
int alpha = 10; //< Simple contrast control
int beta = 0; //< Simple brightness control
string impath = "D:\\CV\\13.jpg"; //1 2 7 8 13
string im_bgpath = "D:\\CV\\13_bg.jpg";
Mat image = imread(impath); //"D:\\CV\\01.jpg"
Mat new_image = Mat::zeros(image.size(), image.type()); //创建新的图像
int value = 10;
Mat image_bg, front_mask;
void Backgroundsustraction(int,void*) {
//cout << "value:" << value << "\n";
//计算两幅图片差异位置的RGB值输出到front_mask中
cv::absdiff(image, image_bg, front_mask);
/* imshow("New Image", front_mask);
waitKey(0);*/
//通过每个通道的平方和最后开方设定阈值
for (int y = 0; y < image.rows; y++) {
for (int x = 0; x < image.cols; x++) {
int tsum = 0;
for (int c = 0; c < 3; c++) {
tsum += front_mask.at<Vec3b>(y, x)[c]* front_mask.at<Vec3b>(y, x)[c];
}
tsum = sqrt(tsum);
if (tsum < value) {
front_mask.at<Vec3b>(y, x)[0] = 0; front_mask.at<Vec3b>(y, x)[1] = 0; front_mask.at<Vec3b>(y, x)[2] = 0;
}
else {
front_mask.at<Vec3b>(y, x)[0] = 255; front_mask.at<Vec3b>(y, x)[1] = 255; front_mask.at<Vec3b>(y, x)[2] = 255;
}
}
}
Mat new_front_mask = Mat::zeros(front_mask.size(), front_mask.type());
Mat new_front_mask2 = Mat::zeros(front_mask.size(), front_mask.type());
cv::medianBlur(front_mask, new_front_mask, 3);
//cv::Canny(new_front_mask, new_front_mask2, 1, 3, 3);
namedWindow("After blur Image", WINDOW_AUTOSIZE);//去噪声
imshow("New Image", front_mask);
imshow("After blur Image", new_front_mask);
}
int main(int, char** argv)
{
image_bg = imread(im_bgpath);
front_mask = Mat::zeros(image.size(), image.type());
namedWindow("Original Image", WINDOW_AUTOSIZE);
namedWindow("New Image", WINDOW_AUTOSIZE);
createTrackbar("threshold", "New Image", &value, 1000, Backgroundsustraction);
Backgroundsustraction(value,0);
imshow("Original Image", image);
waitKey(0);
return 0;
}
contrast:
//-----------------------------------【头文件包含部分】---------------------------------------
// 描述:包含程序所依赖的头文件
//----------------------------------------------------------------------------------------------
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
//-----------------------------------【命名空间声明部分】---------------------------------------
// 描述:包含程序所使用的命名空间
//-----------------------------------------------------------------------------------------------
using namespace std;
using namespace cv;
//-----------------------------------【全局函数声明部分】--------------------------------------
// 描述:全局函数声明
//-----------------------------------------------------------------------------------------------
static void ContrastAndBright(int, void*);
//-----------------------------------【全局变量声明部分】--------------------------------------
// 描述:全局变量声明
//-----------------------------------------------------------------------------------------------
int g_nContrastValue; //对比度值
int g_nBrightValue; //亮度值
Mat g_srcImage, g_dstImage;
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main1()
{
//改变控制台前景色和背景色
//system("color 2F");
// 读入用户提供的图像
g_srcImage = imread("D:\\CV\\IP_data\\bgs_data\\13.jpg");//2 7 8 13
if (!g_srcImage.data) { printf("读取g_srcImage图片错误~! \n"); return false; }
g_dstImage = Mat::zeros(g_srcImage.size(), g_srcImage.type());
//设定对比度和亮度的初值
g_nContrastValue = 80;
g_nBrightValue = 80;
//创建窗口
namedWindow("【效果图窗口】", 1);
//创建轨迹条
createTrackbar("对比度:", "【效果图窗口】", &g_nContrastValue, 300, ContrastAndBright); // 取值0~300
createTrackbar("亮 度:", "【效果图窗口】", &g_nBrightValue, 200, ContrastAndBright); // 取值0~200
//调用回调函数
ContrastAndBright(g_nContrastValue, 0);
ContrastAndBright(g_nBrightValue, 0);
//输出一些帮助信息
cout << endl << "\t运行成功,请调整滚动条观察图像效果\n\n"
<< "\t按下“q”键时,程序退出\n";
//按下“q”键时,程序退出
while (char(waitKey(1)) != 'q') {}
return 0;
}
//-----------------------------【ContrastAndBright( )函数】------------------------------------
// 描述:改变图像对比度和亮度值的回调函数
//-----------------------------------------------------------------------------------------------
static void ContrastAndBright(int, void*)
{
// 创建窗口
namedWindow("【原始图窗口】", 1);
// 三个for循环,执行运算 g_dstImage(i,j) = a*g_srcImage(i,j) + b
for (int y = 0; y < g_srcImage.rows; y++)
{
for (int x = 0; x < g_srcImage.cols; x++)
{
for (int c = 0; c < 3; c++)
{
// sigmoid 函数控制对比度, 常量g_nBrightValue控制亮度
double t = ((g_srcImage.at<Vec3b>(y, x)[c] - 127) / 225.00) * g_nContrastValue * 0.1;
g_dstImage.at<Vec3b>(y, x)[c] = saturate_cast<uchar>(g_srcImage.at<Vec3b>(y, x)[c] * ((1.00 / (1.00 + exp(-t))) + 0.5) + g_nBrightValue - 100);
}
}
}
// 显示图像
imshow("【原始图窗口】", g_srcImage);
imshow("【效果图窗口】", g_dstImage);
}