首页 > 代码库 > opencv实现gamma灰阶检測

opencv实现gamma灰阶检測

简单介绍

  本篇解说使用opencv来測试,表示camera gamma參数的灰阶卡图片指标:YA Block、DynamicRange、Gray Scale。

详细实现

实现代码

#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv/cv.h>
#include "opencv2/imgproc/imgproc.hpp"
 
#define barPic "barPic"
#define Pic_windosw "src"
 
using namespace cv;
char pic_name[20];
char pic_tmp[20] = "tmp.jpg";
char pic_windows[20] = "src";
Mat src, src2;
int src2_width = 400, src2_height = 400;
int width, height, roi_width, roi_height;
int rect[4];
bool mouse_flag = false, ROI_flag = false;
Mat imageROI;
double white=0, black=0, graySum = 0; 
CvFont font;    
double hScale=1;   
double vScale=1;    
int lineWidth=1;
char showWhite[20] = "White:0", showBlack[20]="Black:0", grayNumber[20]="grayNumber:0";
 
void doGammaForA_black(Mat image){
	int i, j, k;
	IplImage pI_1, pI_2;
	CvScalar s;
	roi_width = image.rows;
	roi_height = image.cols;
	Mat src = Mat(roi_width, roi_height, CV_8UC1, 1);
	white = 0;
	black = 0;
 
	pI_1 = image;
	pI_2 = src;
	cvCvtColor(&pI_1, &pI_2, CV_BGR2GRAY);
 
	for(i=0; i<roi_width; i++){
		for(j=0; j<10; j++){
			s = cvGet2D(&pI_2, i, j);
			if(white==0){
				white = s.val[0];
			}else{
				white = (white + s.val[0]) / 2;	
			}
		}
		for(k=roi_height-10; k< roi_height; k++){
			s = cvGet2D(&pI_2, i, k);
			if(black==0){
				black = s.val[0];
			}else{
				black = (black + s.val[0]) / 2;	
			}	
		}
	}
	sprintf(showWhite, "White:%d", (int)white);
	sprintf(showBlack, "Black:%d", (int)black);
}
 
void doGammaForGrayNumber(Mat image){
	int i, j, k, num=0;
	double tmp=0, cur_tmp=0;
	IplImage pI_1, pI_2;
	CvScalar s;
	roi_width = image.rows;
	roi_height = image.cols;
	Mat src = Mat(roi_width, roi_height, CV_8UC1, 1);
	graySum = 0;
 
	pI_1 = image;
	pI_2 = src;
	cvCvtColor(&pI_1, &pI_2, CV_BGR2GRAY);
 
	for(j=0; j<roi_height; j++){
		for(i=0; i<roi_width; i++){
			s = cvGet2D(&pI_2, i, j);
			if(cur_tmp==0){
				cur_tmp=s.val[0];
			}else{
				cur_tmp=(cur_tmp + s.val[0]) / 2;
			}
		}
		if(num >= 3){
			if(tmp - cur_tmp > 8){
				graySum += 1;	
			}
			tmp = cur_tmp;
			cur_tmp = 0;
			num = 0;
		}
		num += 1;
	}
	sprintf(grayNumber, "grayNumber:%d", (int)graySum);
}
 
void on_mouse( int event, int x, int y, int flags, void* ustc)  {    
	switch(event){
		case CV_EVENT_LBUTTONDOWN:
			mouse_flag = true;
			rect[0] = x;
			rect[1] = y;
			rect[2] = 0;
			rect[3] = 0;
			break;
		case CV_EVENT_LBUTTONUP:
			src = imread(pic_name, 1);
			mouse_flag = false;
			rect[2] = x;
			rect[3] = y;
			rectangle(src, Point(rect[0], rect[1]), Point(rect[2], rect[3]), Scalar(0,255,0), 2);
			src = imread(pic_name, 1);
			imageROI = src(cv::Rect(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]));
			ROI_flag = true;
			break;
		case CV_EVENT_MOUSEMOVE:
			if(mouse_flag){
				src = imread(pic_name, 1);
				rectangle(src, Point(rect[0], rect[1]), Point(x, y), Scalar(0,255,0), 2);
				cv::imshow(Pic_windosw, src);
			}
			break;
		default:
			break;
	}
} 
 
int main(int agrc, char* argv[]){
	bool exit = false;
	char c;
	IplImage pI_barPic;
 
	memcpy(pic_name,argv[1],sizeof(argv[1]));
 
	src=cv::imread(pic_name,1);
	width = src.rows;
	height = src.cols;
	src2 = cv::Mat(src2_width, src2_height, CV_8UC3, 1);
	pI_barPic = src2;
	cv::imshow(Pic_windosw, src);
 
	cvInitFont(&font,  CV_FONT_HERSHEY_PLAIN|CV_FONT_ITALIC, hScale, vScale, 0, lineWidth);
	cvPutText(&pI_barPic, showWhite ,cvPoint(10, 15),&font,CV_RGB(255,0,0));
	cvPutText(&pI_barPic, showBlack ,cvPoint(10, 30),&font,CV_RGB(255,0,0));
	cvPutText(&pI_barPic, grayNumber ,cvPoint(10,45),&font,CV_RGB(255,0,0));
	cv::imshow(barPic, src2);
	cvSetMouseCallback(Pic_windosw, on_mouse, NULL);
	while(!exit){
		c = cv::waitKey(100);
		if(c == ‘q‘){
			exit = true;	
		}
		if(ROI_flag){
			cv::imshow("test", imageROI);
			doGammaForA_black(imageROI);  //A块亮度,动态范围
			doGammaForGrayNumber(imageROI);//Gray Scale
			cvZero(&pI_barPic);
			cvPutText(&pI_barPic, showWhite ,cvPoint(10, 15),&font,CV_RGB(255,0,0));
			cvPutText(&pI_barPic, showBlack ,cvPoint(10, 30),&font,CV_RGB(255,0,0));
			cvPutText(&pI_barPic, grayNumber ,cvPoint(10,45),&font,CV_RGB(255,0,0));
			cv::imshow(barPic, src2);
			ROI_flag = false;
		}
 
	}
	cvDestroyAllWindows();  
 
	return 0;  
}

代码解说

  1、首先也是进行各类初始化。导入了须要处理的灰阶卡照片src。生成一张空白照片src2用来显示结果。接着用cvInitFont初始化字体显示。
依次的三个cvPutText,将YA Block、DynamicRange、Gray Scale的显示。初始化到src2相应位置。然后给src显示窗体,绑定鼠标响应函数。最后是
一个循环,在循环中,首先等待键值,假设输入键值‘q‘,就直接退出程序。接着推断ROI_flag是否为true,是的话就进入相应操作。不是就直接跳过。
src=cv::imread(pic_name,1);
	width = src.rows;
	height = src.cols;
	src2 = cv::Mat(src2_width, src2_height, CV_8UC3, 1);
	pI_barPic = src2;
	cv::imshow(Pic_windosw, src);
 
	cvInitFont(&font,  CV_FONT_HERSHEY_PLAIN|CV_FONT_ITALIC, hScale, vScale, 0, lineWidth);
	cvPutText(&pI_barPic, showWhite ,cvPoint(10, 15),&font,CV_RGB(255,0,0));
	cvPutText(&pI_barPic, showBlack ,cvPoint(10, 30),&font,CV_RGB(255,0,0));
	cvPutText(&pI_barPic, grayNumber ,cvPoint(10,45),&font,CV_RGB(255,0,0));
	cv::imshow(barPic, src2);
	cvSetMouseCallback(Pic_windosw, on_mouse, NULL);
	while(!exit){
		c = cv::waitKey(100);
		if(c == ‘q‘){
			exit = true;	
		}
		if(ROI_flag){
		     .............
                     .............
                     .............
		}
 
	}
}
  2、在鼠标响应函数中,操作非常easy,就是让用户框选中灰阶卡所在的位子。

当用户左键按下的时候,随着鼠标的拖动,会出现一个绿色的矩形框。 当鼠标左键抬起之后,当前矩形框的位置,就被觉得是灰阶卡所在的位置。

同一时候将标志位ROI_flag设置为true。

void on_mouse( int event, int x, int y, int flags, void* ustc)  {    
	switch(event){
		case CV_EVENT_LBUTTONDOWN:
			mouse_flag = true;
			rect[0] = x;
			rect[1] = y;
			rect[2] = 0;
			rect[3] = 0;
			break;
		case CV_EVENT_LBUTTONUP:
			src = imread(pic_name, 1);
			mouse_flag = false;
			rect[2] = x;
			rect[3] = y;
			rectangle(src, Point(rect[0], rect[1]), Point(rect[2], rect[3]), Scalar(0,255,0), 2);
			src = imread(pic_name, 1);
			imageROI = src(cv::Rect(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]));
			ROI_flag = true;
			break;
		case CV_EVENT_MOUSEMOVE:
			if(mouse_flag){
				src = imread(pic_name, 1);
				rectangle(src, Point(rect[0], rect[1]), Point(x, y), Scalar(0,255,0), 2);
				cv::imshow(Pic_windosw, src);
			}
			break;
		default:
			break;
	}
}
  3、之前有提到,当ROI_flag置为true之后。就会进入相应处理函数中,首先是使用doGammaForA_black(imageROI);对框选出来的灰阶卡进行
YA Block、DynamicRange的检測。
    检測的方式是,首先将灰阶卡图片灰阶化,然后分别取出图片最左边的10列,计算它平均亮度作为YA Block;取出图片最右边10列,也是计算它们的
平均亮度最为最暗处亮度,当左边平均亮度减去右边平均亮度。得到的就是DynamicRange。
void doGammaForA_black(Mat image){
	int i, j, k;
	IplImage pI_1, pI_2;
	CvScalar s;
	roi_width = image.rows;
	roi_height = image.cols;
	Mat src = Mat(roi_width, roi_height, CV_8UC1, 1);
	white = 0;
	black = 0;
 
	pI_1 = image;
	pI_2 = src;
	cvCvtColor(&pI_1, &pI_2, CV_BGR2GRAY);
 
	for(i=0; i<roi_width; i++){
		for(j=0; j<10; j++){
			s = cvGet2D(&pI_2, i, j);
			if(white==0){
				white = s.val[0];
			}else{
				white = (white + s.val[0]) / 2;	
			}
		}
		for(k=roi_height-10; k< roi_height; k++){
			s = cvGet2D(&pI_2, i, k);
			if(black==0){
				black = s.val[0];
			}else{
				black = (black + s.val[0]) / 2;	
			}	
		}
	}
	sprintf(showWhite, "White:%d", (int)white);
	sprintf(showBlack, "Black:%d", (int)black);
}
  4、最后是使用doGammaForGrayNumber(imageROI),进行Gray Scale的计算。计算的方式是:首先将灰阶卡图片灰阶化,然后从左往右遍历整个图片。
以3列为一组的计算出它们的平均亮度。当相邻两块的亮度差值大于8的时候,表示Gray Scale加1.
void doGammaForGrayNumber(Mat image){
	int i, j, k, num=0;
	double tmp=0, cur_tmp=0;
	IplImage pI_1, pI_2;
	CvScalar s;
	roi_width = image.rows;
	roi_height = image.cols;
	Mat src = Mat(roi_width, roi_height, CV_8UC1, 1);
	graySum = 0;
 
	pI_1 = image;
	pI_2 = src;
	cvCvtColor(&pI_1, &pI_2, CV_BGR2GRAY);
 
	for(j=0; j<roi_height; j++){
		for(i=0; i<roi_width; i++){
			s = cvGet2D(&pI_2, i, j);
			if(cur_tmp==0){
				cur_tmp=s.val[0];
			}else{
				cur_tmp=(cur_tmp + s.val[0]) / 2;
			}
		}
		if(num >= 3){
			if(tmp - cur_tmp > 8){
				graySum += 1;	
			}
			tmp = cur_tmp;
			cur_tmp = 0;
			num = 0;
		}
		num += 1;
	}
	sprintf(grayNumber, "grayNumber:%d", (int)graySum);
}

效果演示

 相应的效果演演示样例如以下:
        技术分享
        技术分享
        技术分享

opencv实现gamma灰阶检測