圖像亮度增強(qiáng)
圖像的亮度變化脑豹,簡(jiǎn)單來說就是對(duì)圖像像素的線性變化研叫,公式如下所示:
其中,表示第
行处铛,第
列的像素值赖晶,
表示亮度變換后的像素值。綜上,圖像亮度變化的代碼如下:
static const double alpha = 1.5;
static const double beta = -90;
void highLigh(Mat& img,int x0,int y0,int x1,int y1) //指定區(qū)域進(jìn)行亮度調(diào)整
{
for (int i=x0;i<x1;i++)
{
for (int j = y0; j < y1; j++)
{
for (int c = 0; c < 3; c++)
{
img.at<Vec3b>(j, i)[c] = saturate_cast<uchar>(img.at<Vec3b>(j, i)[c] * alpha + beta);
}
}
}
}
指定區(qū)域的亮度增強(qiáng)和直方圖繪制
對(duì)于一副圖像有如下要求:
- 加載并顯示圖像,通過鼠標(biāo)左鍵拖拽選定指定區(qū)域扯旷,當(dāng)釋放左鍵時(shí),對(duì)選定的區(qū)域?qū)崿F(xiàn)亮度增強(qiáng)索抓。
- 對(duì)選定的區(qū)域?qū)崿F(xiàn)直方圖繪制钧忽,橫軸每個(gè)單位區(qū)間指定為32個(gè)像素值(即0-31,32-63…,224-255)逼肯,而縱軸顯示為區(qū)間像素出現(xiàn)的次數(shù)耸黑。對(duì)于一副RGB三通道圖像,用紅色表示R通道的直方圖分布篮幢,綠色表示G通道的像素分布大刊,藍(lán)色表示B通道。
針對(duì)以上問題三椿,利用C++和opencv實(shí)現(xiàn)的代碼如下所示:
#include<iostream>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include<opencv2/opencv.hpp>
using namespace cv;
/*
create a program that reads in and displays an image.
a. Allow the user to select a rectangular region in the image by drawing a rectangle with the mouse button held down
and highlight the region when the mouse button is released.Be careful to save an image copy in memory so that your
drawing into the image dose not destory the original values there. The next mouse click should start the process all
over again from the original image
b. In a separate window,use the drawing functions to draw a graph in blue,green,and red that represents how many pixels
of each value were found in the selected box.This is the color histofram of that color region.The x-axis should be eight
bins that represent pixel values falling within the ranges 0-31,32-63,…,223-255.The y-axis should be counts of the number
of pixels that were found ub that bin range.Do this for each color channel.BGR.
*/
Point2i initP(0, 0); // 記錄初始點(diǎn)坐標(biāo)
static const double alpha = 1.5;
static const double beta = -90;
void highLigh(Mat& img,int x0,int y0,int x1,int y1) //指定區(qū)域進(jìn)行亮度調(diào)整
{
for (int i=x0;i<x1;i++)
{
for (int j = y0; j < y1; j++)
{
for (int c = 0; c < 3; c++)
{
img.at<Vec3b>(j, i)[c] = saturate_cast<uchar>(img.at<Vec3b>(j, i)[c] * alpha + beta);
}
}
}
}
void histGraph(Mat& histMat,Mat& histImg, const int& width,const Scalar& rgb)
{
double maxVal = 0;
minMaxLoc(histMat, 0, &maxVal, 0, 0);
for (int h = 0; h < width; h++)
{
int value = cvRound(histImg.rows * 0.9 * histMat.at<float>(h) / maxVal);
rectangle(histImg, Point(h * (histImg.cols/width), (histImg.rows - 1)), Point((h + 1) * (histImg.cols/width), histImg.rows - 1 - value), rgb, -1);
}
}
void HandlerMouseEvent(int event,int x,int y,int flags,void *p)
{
Mat srcImg = *(static_cast<Mat*>(p));
Mat cloneImg = srcImg.clone();
//Mat histdigram;
const int channels[] = { 0,1,2 }; //繪制直方圖:3個(gè)通道
int bins_ranges[] = {32};
MatND m_hist; //直方圖輸出
float hranges[] = { 0,256 };
const float* ranges[] = {hranges}; //直方圖縱軸
switch (event)
{
case EVENT_LBUTTONDOWN:
{
initP.x = x;
initP.y = y;
break;
}
case (EVENT_MOUSEMOVE && (flags&EVENT_FLAG_LBUTTON)):
{
rectangle(cloneImg, Rect2i(initP, Point2i(x, y)), Scalar(233, 233, 84), 1, 8, 0);
//highLigh(cloneImg, initP.x, initP.y, x, y);
imshow("SelectRectImage", cloneImg);
break;
}
case EVENT_LBUTTONUP:
{
highLigh(cloneImg, initP.x, initP.y, x, y);
imshow("selectRectImage", cloneImg);
//畫直方圖
Mat histdigram = Mat(cloneImg, Rect(initP, Point2d(x, y)));
std::vector<Mat> bgr_channels;
split(histdigram, bgr_channels); //通道分離
Mat m_hist1, m_hist2, m_hist3;
calcHist(&bgr_channels[0], 1, 0, Mat(), m_hist1, 1, bins_ranges, ranges, true, false);
calcHist(&bgr_channels[1], 1, 0, Mat(), m_hist2, 1, bins_ranges, ranges, true, false);
calcHist(&bgr_channels[2], 1, 0, Mat(), m_hist3, 1, bins_ranges, ranges, true, false);
Mat histImg = Mat::zeros(512, 512, CV_8UC3);
histGraph(m_hist1, histImg, bins_ranges[0], Scalar(255, 0, 0));
histGraph(m_hist2, histImg, bins_ranges[0], Scalar(0, 255, 0));
histGraph(m_hist3, histImg, bins_ranges[0], Scalar(0, 0, 255));
imshow("HistTest", histImg);
break;
}
}
}
int main()
{
Mat img = imread("ex3.jpg");
namedWindow("SelectRectImage",0);
namedWindow("HistTest"); //顯示直方圖視圖
setMouseCallback("SelectRectImage", HandlerMouseEvent,&img);
HandlerMouseEvent(0, 0, 0, 1,&img);
imshow("SelectRectImage", img);
waitKey(0);
return 0;
}
根據(jù)以上代碼缺菌,實(shí)現(xiàn)效果如下:
對(duì)選定ROI區(qū)域進(jìn)行亮度增強(qiáng),并繪制ROI區(qū)域的直方圖
注意:直方圖繪制中赋续,利用了
opencv
提供的calchist()
函數(shù)男翰,對(duì)于此函數(shù)的參數(shù)參數(shù)另患,有如下解釋:
void cv::calchist(const Mat* images, //輸入圖像(源圖像)纽乱,具有相同的深度和尺寸
int nimages, //輸出圖像的數(shù)量
const int* channels, //通道數(shù)量,對(duì)于多幅圖像而言昆箕,第一個(gè)圖像的通道數(shù)為0-images[0].channels(),第二個(gè)數(shù)組通道為images[0].channels()-images[0].channels()+images[1].channels()-1,以此類推
inputArray mask, //可選參數(shù)鸦列,一般默認(rèn)為Mat(),如果不為空,設(shè)定為與images[i]相同的尺寸
outputArray hist, //直方圖輸出,一個(gè)密集或稀疏矩陣
int dims, // 直方圖的維數(shù)鹏倘,必須是正值且大于 CV_MAX_DIMS
const int* histSIze, //直方圖每一個(gè)維度的大小
const float** ranges, // 每個(gè)維度中直方圖bin邊界的dims數(shù)組薯嗤。 當(dāng)直方圖是均勻的時(shí)(uniform = true),則對(duì)于每個(gè)維度i纤泵,足以指定第0個(gè)直方圖bin的下(包含)邊界L0和上界(專有)邊界UhistSize [i] -1 最后一個(gè)直方圖bin histSize [i] -1骆姐。 也就是說,在均勻的直方圖的情況下捏题,range [i]中的每個(gè)都是2個(gè)元素的數(shù)組玻褪。 當(dāng)直方圖不一致時(shí)(均等= false),則每個(gè)range [i]都包含histSize [i] +1個(gè)元素:L0公荧,U0 = L1带射,U1 = L2,...循狰,UhistSize [i] -2 = LhistSize [i] -1窟社,UhistSize [i] -1券勺。 不在L0和UhistSize [i] -1之間的數(shù)組元素不計(jì)入直方圖。
bool uniform = true, // 是否均勻分布
bool accumulate=false //累加標(biāo)記灿里,當(dāng)設(shè)置為1時(shí)关炼,當(dāng)分配直方圖時(shí),不會(huì)清楚初始狀態(tài)匣吊,此功能可以從幾組數(shù)組中計(jì)算單個(gè)直方圖或者及時(shí)更新直方圖盗扒。
)