OpenCV(3)程序时间测量、色彩映射、LUT、图像反转 C++

1. 如何使用OpenCV扫描图像,查找表格和时间测量

2. (cv::getTickCount) 和 (cv::getTickFrequency)计时函数

double t1 = (double)getTickCount();	//计时开始
...  								//需要计时的程序
double t2 = (double)getTickCount();	//计时结束
cout<<"time:"<<(t2-t1)/(getTickFrequency())<<endl;	//时间输出

例1:

#include
#include
#include
using namespace std;
using namespace cv;
int main(void)
{
	// 计时开始
	double t1 = (double)getTickCount();	
	Mat R = Mat(5, 5, CV_8UC3);	//用随机值填充一个矩阵
	randu(R, Scalar::all(0), Scalar::all(255));
	cout << "R (default) = " << endl << R << endl << endl;
	// 计时结束
	double t2 = (double)getTickCount();	
	// 时间输出
	cout << "运行时间:" << (t2 - t1) / (getTickFrequency()) << "秒" << endl;
	return 0;
}

执行结果:

R (default) =
[ 91,   2,  79, 179,  52, 205, 236,   8, 181, 239,  26, 248, 207, 218,  45;
 183, 158, 101, 102,  18, 118,  68, 210, 139, 198, 207, 211, 181, 162, 197;
 191, 196,  40,   7, 243, 230,  45,   6,  48, 173, 242, 125, 175,  90,  63;
  90,  22, 112, 221, 167, 224, 113, 208, 123, 214,  35, 229,   6, 143, 138;
  98,  81, 118, 187, 167, 140, 218, 178,  23,  43, 133, 154, 150,  76, 101]

运行时间:0.0028112

3. (cv :: LUT)函数

在图像处理中,很常见的是要将所有给定的图像值修改为其他值。OpenCV提供了修改图像值的功能,无需编写图像的扫描逻辑。我们使用核心模块的cv :: LUT()函数。首先我们构建一个Mat类型的查找表:

 Mat lookUpTable(1, 256, CV_8U);
    uchar* p = lookUpTable.ptr();
    for( int i = 0; i < 256; ++i)
        p[i] = table[i];

最后调用函数(我是我们的输入图像,J是输出的一个):

LUT(I,lookUpTable,J);

1. opencv 2中的LUT函数为

 void LUT(InputArray src, InputArray lut, OutputArray dst,int   interpolation);
  • src表示的是输入图像(可以是单通道也可是3通道)
  • lut表示查找表(查找表也可以是单通道,也可以是3通道,如果输入图像为单通道,那查找表必须为单通道,若输入图像为3通道,查找表可以为单通道,也可以为3通道,若为单通道则表示对图像3个通道都应用这个表,若为3通道则分别应用 )
  • dst表示输出图像,
  • interpolation表示插值,这个参数没有用,源代码里面也没有用它,默认为0就行,传其他值会报错。

2. opencv3里面的LUT函数

void LUT(InputArray src, InputArray lut, OutputArray dst);

和2一样,不过没有了interpolation这个参数。

1. 单通道图片处理:

#include
using namespace cv;
int main()
{
	//查找表,数组的下标对应图片里面的灰度值
	//例如lutData[20]=0;表示灰度为20的像素其对应的值0.
	//可能这样说的不清楚仔细看下代码就清楚了。
	uchar lutData[256];
	for (int i = 0; i < 256; i++)
	{
		if (i <= 100)
			lutData[i] = 0;	//0-100灰度的像素灰度变成0
		if (i > 100 && i <= 200)
			lutData[i] = 100;	//101-200的像素灰度变成100
		if (i > 200)
			lutData[i] = 255;	//201-255的像素灰度变成255
	}
	Mat lut(1, 256, CV_8UC1, lutData);
	Mat a = imread("../data/test2.jpg", IMREAD_GRAYSCALE);
	Mat b;
	namedWindow("anjis", WINDOW_AUTOSIZE);
	namedWindow("anjis1", WINDOW_AUTOSIZE);
	imshow("anjis", a);
	LUT(a, lut, b);
	imshow("anjis1", b);
	waitKey();
}

执行结果:
OpenCV(3)程序时间测量、色彩映射、LUT、图像反转 C++_第1张图片

2. 三通道彩色图像源代码:

#include
using namespace cv;
int main()
{
	uchar lutData[256 * 3];
	for (int i = 0; i < 256; i++)
	{
		if (i <= 100)
		{
			lutData[i * 3] = 0;	  //R通道的0-100灰度的像素灰度变成0
			lutData[i * 3 + 1] = 50;//G通道的0-100灰度的像素灰度就变成50
			lutData[i * 3 + 2] = 50;//B通道的0-100灰度的像素灰度就变成50
		}
		if (i > 100 && i <= 200)
		{
			lutData[i * 3] = 100;	  //R通道的101-200灰度的像素灰度变成100
			lutData[i * 3 + 1] = 10;//G通道的101-200灰度的像素灰度就变成10
			lutData[i * 3 + 2] = 200;//B通道的101-200灰度的像素灰度就变成200
		}
		if (i > 200)
		{
			lutData[i * 3] = 255;	   //R通道的201-255灰度的像素灰度变成255
			lutData[i * 3 + 1] = 200;//G通道的201-255灰度的像素灰度就变成200
			lutData[i * 3 + 2] = 100;//B通道的201-255灰度的像素灰度就变成100
		}
	}
	Mat lut(1, 256, CV_8UC3, lutData);
	Mat a = imread("../data/test2.jpg", IMREAD_COLOR);
	Mat b;
	namedWindow("anjis", WINDOW_AUTOSIZE);
	namedWindow("anjis1", WINDOW_AUTOSIZE);
	imshow("anjis", a);
	LUT(a, lut, b);
	imshow("anjis1", b);
	waitKey();
}

执行结果:
OpenCV(3)程序时间测量、色彩映射、LUT、图像反转 C++_第2张图片

3. 图像像素的读写操作

3.1. 手动遍历实现图像反转

(cv :: invert)是opencv自带的求解逆矩阵或者伪逆矩阵的函数
double invert(InputArray src, OutputArraydst, int flags=DECOMP_LU);
  • src: 输入,浮点型(32位或者64位)的M×N的矩阵,当参数3的使用方法为DECOMP_CHOLESKY DECOMP_LU
    DECOMP_EIG时函数功能为求逆,此时需保证M=N(参见参数flag)
  • dst: 输出,与输入矩阵类型一致的N×M的矩阵
  • flag:求逆方法,提供4种可选择的方法:DECOMP_CHOLESKY(基于CHOLESKY分解的方法),
    DECOMP_LU(基于LU分解的方法), DECOMP_EIG(基于特征值分解的方法),
    DECOMP_SVD(基于奇异值分解的方法)。其中,前三种方法要求输入的矩阵必须为方阵,此时计算结果为矩阵的逆;最后一种方法为对非方阵的伪逆计算,对矩阵的形状没有要求。函数接口的默认参数为DECOMP_LU方法

图像取反:反转图像的像素强度,使图像中的前景变为背景,背景变为前景。
显然这是一个一对一的映射,即像素值0变为255,1变为254…254变为1,255变为0。对应的查找表为lookup[256]={255,254,…,1,0}。

#include 
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace std;
using namespace cv;
void Invert(Mat& img, const uchar* const lookup)
{
    int rows = img.rows;
    int cols = img.cols * img.channels();
    for (int i = 0; i < rows; i++)
    {
        uchar* p = img.ptr<uchar>(i);
        for (int j = 0; j < cols; j++)
            p[j] = lookup[p[j]];
    }
}
int main()
{
    Mat src = imread("../data/test2.jpg");  //将任意一张名为test.jpg的图片放置于工程文件夹test中
    if (!src.data)
    {
        cout << "error! The image is not built!" << endl;
        return -1;
    }
    // 为了演示效果,将图片转换成灰度图片
    Mat img1 = src;
    //cvtColor( src, img1, CV_RGB2GRAY );
    imshow("First", img1);
    //建立查找表
    uchar lookup[256];
    for (int i = 0; i < 256; i++)
        lookup[i] = 255 - i;
    //调用自定义图像取反函数
    Invert(img1, lookup);
    imshow("Second", img1);
    waitKey();
    return 0;
}

3.2. LUT函数实现图像反转

#include
#include
#include
#include
using namespace std;
using namespace cv;
int main()
{
    Mat src = imread("../data/test2.jpg");  //将任意一张名为test.jpg的图片放置于工程文件夹test中
    if (!src.data)
    {
        cout << "error! The image is not built!" << endl;
        return -1;
    }
    // 为了演示效果,将图片转换成灰度图片
    Mat img1 = src;
    //cvtColor( src, img1, CV_RGB2GRAY );
    imshow("First", img1);
    //建立查找表
    Mat lookUpTable(1, 256, CV_8U);
    uchar* p = lookUpTable.data;
    for (int i = 0; i < 256; i++)
        p[i] = 255 - i;
    //通过LUT函数实现图像取反
    LUT(img1, lookUpTable, img1);
    imshow("Second", img1);
    waitKey();
    return 0;
}

执行结果:
OpenCV(3)程序时间测量、色彩映射、LUT、图像反转 C++_第3张图片

3.3.图像像素的读写操作

本次对像素的操作一共使用了6种方法,并进行计时对比,最终Opencv中的Copy方式速度是最快的,次之是指针遍历方式。
有一点就是为什么迭代的方式会比数组遍历的方式还要慢那么多,正常应该是比数组快一些才是正确的。

(cv :: copyByArrayWay)数组at遍历方式
(cv :: copyByRowPtrWay)行指针遍历方式
(cv :: copyByPtrWay)指针遍历方式
(cv :: copyByIteratorWay)迭代方式
(cv :: copyByOpenCv)OpenCv copy方式
数组遍历方式耗时: 0.3496毫秒
行指针遍历方式耗时: 0.2317毫秒
指针遍历方式耗时: 0.3716毫秒
迭代方式耗时: 0.5014毫秒
Opencv copy方式耗时: 0.1565毫秒
LUT方式耗时: 0.4273毫秒
#include "opencv2\opencv.hpp"
#include 
using namespace std;
using namespace cv;
bool copyByArrayWay(Mat srcImg, Mat& resultImg);//数组at遍历方式
bool copyByRowPtrWay(Mat srcImg, Mat& resultImg);//行指针遍历方式
bool copyByPtrWay(Mat srcImg, Mat& resultImg);//指针遍历方式
bool copyByIteratorWay(Mat srcImg, Mat& resultImg);//迭代方式
bool copyByOpenCv(Mat srcImg, Mat& resultImg);//OpenCv copy方式
int main(int argv, char** argc)
{
    Mat src = imread("../data/test2.jpg");
    if (src.empty())
    {
        printf("Could not load image...\n");
        return -1;
    }
    int64 startTime, endTime;
    double usedTime;
    数组遍历方式
    Mat arrayWayResult = Mat::zeros(src.size(), src.type());
    startTime = getTickCount();     //计时开始
    copyByArrayWay(src, arrayWayResult);//数组遍历方式
    endTime = getTickCount();       //计时结束
    usedTime = (endTime - startTime) / getTickFrequency() * 1000;//计算时间
    cout << "数组遍历方式耗时:" << usedTime << "毫秒" << endl;//时间输出
    imshow("arrayWay", arrayWayResult);//在OpenCV窗口中显示图像
    行指针遍历方式
    Mat rowPtrWayResult = Mat::zeros(src.size(), src.type());
    startTime = getTickCount();     //计时开始
    copyByRowPtrWay(src, rowPtrWayResult);//行指针遍历方式
    endTime = getTickCount();       //计时结束
    usedTime = (endTime - startTime) / getTickFrequency() * 1000;//计算时间
    cout << "行指针遍历方式耗时:" << usedTime << "毫秒" << endl;//时间输出
    imshow("rowPtrWay", rowPtrWayResult);//在OpenCV窗口中显示图像
    指针方式遍历
    Mat ptrWayResult = Mat::zeros(src.size(), src.type());
    startTime = getTickCount();     //计时开始
    copyByPtrWay(src, ptrWayResult); //指针方式遍历
    endTime = getTickCount();       //计时结束
    usedTime = (endTime - startTime) / getTickFrequency() * 1000;//计算时间
    cout << "指针遍历方式耗时:" << usedTime << "毫秒" << endl;//时间输出
    imshow("ptrWay", ptrWayResult); //在OpenCV窗口中显示图像
    迭代方式遍历
    Mat iterWayResult = Mat::zeros(src.size(), src.type());
    startTime = getTickCount();     //计时开始
    copyByIteratorWay(src, iterWayResult);//迭代方式遍历
    endTime = getTickCount();       //计时结束
    usedTime = (endTime - startTime) / getTickFrequency() * 1000;//计算时间
    cout << "迭代方式耗时:" << usedTime << "毫秒" << endl;//时间输出
    imshow("iterWay", iterWayResult);//在OpenCV窗口中显示图像
    OpenCv copy方式
    Mat copyWayResult = Mat::zeros(src.size(), src.type());
    startTime = getTickCount();     //计时开始
    copyByOpenCv(src, copyWayResult);//OpenCv copy方式
    endTime = getTickCount();       //计时结束
    usedTime = (endTime - startTime) / getTickFrequency() * 1000;//计算时间
    cout << "Opencv copy方式耗时:" << usedTime << "毫秒" << endl;//时间输出
    imshow("OpencvCopyWay", copyWayResult);//在OpenCV窗口中显示图像
	LUT方式
    Mat lookUpTable(1, 256, CV_8U);
    startTime = getTickCount();     //计时开始
    uchar* p = lookUpTable.data;
    for (int i = 0; i < 256; ++i)
        p[i] = i;
    LUT(src, lookUpTable, src);     //LUT
    endTime = getTickCount();       //计时结束
    usedTime = (endTime - startTime) / getTickFrequency() * 1000;//计算时间
    cout << "LUT方式耗时: " << usedTime << "毫秒" << endl;//时间输出
    imshow("LUT Way", src);//在OpenCV窗口中显示图像    
    waitKey(0);
    return 0;
}
//数组遍历方式 at
bool copyByArrayWay(Mat srcImg, Mat& resultImg)
{
    if (srcImg.empty())
    {
        printf("Could not load image...\n");
        return false;
    }
    int rows = srcImg.rows;
    int cols = srcImg.cols;
    int ch = srcImg.channels();
    for (int row = 0; row < rows; row++) {
        for (int col = 0; col < cols; col++) {
            if (ch == 3) {
                resultImg.at<Vec3b>(row, col) = srcImg.at<Vec3b>(row, col);
            }
            else if (ch == 1) {
                resultImg.at<uchar>(row, col) = srcImg.at<uchar>(row, col);
            }
        }
    }
    return true;
}
//行指针遍历方式
bool copyByRowPtrWay(Mat srcImg, Mat& resultImg)
{
    if (srcImg.empty())
    {
        printf("Could not load image...\n");
        return false;
    }
    int rows = srcImg.rows;
    int rowPixelNums = (srcImg.cols) * (srcImg.channels());
    for (int row = 0; row < rows; row++) {
        uchar* srcRowPtr = srcImg.ptr<uchar>(row);
        uchar* resultRowPtr = resultImg.ptr<uchar>(row);
        for (int pixelNum = 0; pixelNum < rowPixelNums; pixelNum++) {
            resultRowPtr[pixelNum] = srcRowPtr[pixelNum];
        }
    }
    return true;
}
//指针遍历方式
bool copyByPtrWay(Mat srcImg, Mat& resultImg)
{
    if (srcImg.empty()) {
        printf("Could not load image...\n");
        return false;
    }
    int ch = srcImg.channels();
    int totalPixelNums = (srcImg.rows) * (srcImg.cols) * ch;
    uchar* srcRowPtr = srcImg.ptr<uchar>(0);
    uchar* resultRowPtr = resultImg.ptr<uchar>(0);
    for (int pixel = 0; pixel < totalPixelNums; pixel++) {
        resultRowPtr[pixel] = srcRowPtr[pixel];
    }
    return true;
}
//迭代方式
bool copyByIteratorWay(Mat srcImg, Mat& resultImg)
{
    if (srcImg.empty()) {
        printf("Could not load image...\n");
        return false;
    }
    int ch = srcImg.channels();
    if (ch == 3) {
        Mat_<Vec3b>::iterator srcPtrBegin = srcImg.begin<Vec3b>();
        Mat_<Vec3b>::iterator outPtrBegin = resultImg.begin<Vec3b>();
        Mat_<Vec3b>::iterator srcPtrEnd = srcImg.end<Vec3b>();
        while (srcPtrBegin != srcPtrEnd) {
            *outPtrBegin = *srcPtrBegin;
            srcPtrBegin++;
            outPtrBegin++;
        }
        return true;
    }
    else if (ch == 1) {
        Mat_<uchar>::iterator srcPtrBegin = srcImg.begin<uchar>();
        Mat_<uchar>::iterator outPtrBegin = resultImg.begin<uchar>();
        Mat_<uchar>::iterator srcPtrEnd = srcImg.end<uchar>();
        while (srcPtrBegin != srcPtrEnd) {
            *outPtrBegin = *srcPtrBegin;
            srcPtrBegin++;
            outPtrBegin++;
        }
        return true;
    }
    else
        return false;
}
//OpenCv copy方式
bool copyByOpenCv(Mat srcImg, Mat& resultImg)
{
    if (srcImg.empty()) {
        printf("Could not load image...\n");
        return false;
    }
    srcImg.copyTo(resultImg);
    return true;
}

4.(cv :: applyColorMap) 在OpenCV中对灰度图进行颜色映射,实现数据的色彩化

  • 什么是色彩映射:
    说直白点就是将各种数据映射成颜色信息,例如:温度,高度,压力,密度,湿度,城市拥堵数据等等
    色彩化后更加直观表达
    在OpenCV里可以使用
Mat im_gray = imread("pluto.jpg", IMREAD_GRAYSCALE);
Mat im_color;
applyColorMap(im_gray, im_color, COLORMAP_JET);

这种方式将一个灰度数据安装一定得映射方式对应上一个颜色值,灰度图里存储你的温度数据,高度数据什么的都可以
OpenCV applyColorMap默认的映射方式如下:
OpenCV(3)程序时间测量、色彩映射、LUT、图像反转 C++_第4张图片

#include "opencv2\opencv.hpp"
#include 
using namespace std;
using namespace cv;
void myColorMap(Mat& grayImg);
int main(int argc, char** argv)
{
    Mat src = imread("../data/test2.jpg");
    if (src.empty())
    {
        printf("Could not load image...\n");
        return -1;
    }
    imshow("sourceImg", src);//显示结果
    Mat grayLutDemo, dst;
    //使用LUT
    applyColorMap(src, dst, COLORMAP_HSV);
    imshow("ColorMap", dst);//显示结果
	//自定义颜色映射
    cvtColor(src, grayLutDemo, COLOR_BGR2GRAY);
    myColorMap(grayLutDemo);
    imshow("GrayLutDemo", grayLutDemo);//显示结果
    waitKey(0);
    return 0;
}
void myColorMap(Mat& grayImg)
{
    int lut[256];
    //这个for循环中可以进行其他的操作 使相应的像素值 改变为 指定的像素值
    //这里相当于对单通道图像的像素进行二值化处理
    for (int i = 0; i < 256; i++) 
    {
        if (i < 127) 
        {
            lut[i] = 0;
        }
        else
            lut[i] = 255;
    }
    int hight = grayImg.rows;
    int width = grayImg.cols;
    for (int row = 0; row < hight; row++) 
    {
        for (int col = 0; col < width; col++) 
        {
            uchar pv = grayImg.at<uchar>(row, col);
            grayImg.at<uchar>(row, col) = lut[pv];
        }
    }
}

执行结果:
OpenCV(3)程序时间测量、色彩映射、LUT、图像反转 C++_第5张图片

你可能感兴趣的:(opencv,C/C++,c++,opencv)