码迷,mamicode.com
首页 > 其他好文 > 详细

OpenCV Tutorials —— Scan images

时间:2014-11-16 17:08:55      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:style   http   io   color   ar   os   使用   sp   for   

color space reduction

divide the color space current value with a new input value to end up with fewer colors. For instance every value between zero and nine takes the new value zero, every value between ten and nineteen the value ten and so on.

减少颜色空间数目

Therefore, any fraction will be rounded down. Taking advantage of this fact the upper operation in the uchar domain may be expressed as:

bubuko.com,布布扣

Therefore, for larger images it would be wise to calculate all possible values beforehand and during the assignment just make the assignment, by using a lookup table. Lookup tables are simple arrays (having one or more dimensions) that for a given input value variation holds the final output value.

滤波模板 —— 在需要时分配空间

 

程序中使用 stringstream 来实现txt到int 的转换

int divideWith = 0; // convert our input string to number - C++ style
    stringstream s;
    s << argv[2];
    s >> divideWith;
    if (!s || !divideWith)
    {
        cout << "Invalid number entered for dividing. " << endl;
        return -1;
    }

    uchar table[256];
    for (int i = 0; i < 256; ++i)
       table[i] = (uchar)(divideWith * (i/divideWith));

 

使用 OpenCV 提供的时间计算函数

The first returns the number of ticks of your systems CPU from a certain event (like since you booted your system).

The second returns how many times your CPU emits a tick during a second.

double t = (double)getTickCount();
// do something ...
t = ((double)getTickCount() - t)/getTickFrequency();
cout << "Times passed in seconds: " << t << endl;

 

图像在内存中的存储

注意 RGB图像在内存的存放顺序是BGR

In case of a gray scale image we have something like:

bubuko.com,布布扣

For multichannel images the columns contain as many sub columns as the number of channels. For example in case of an RGB color system:

bubuko.com,布布扣

 

The efficient way

C语言风格,直接操纵指针是最快的,不解释

We need to look out for color images: we have three channels so we need to pass through three times more items in each row.

Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() != sizeof(uchar));

    int channels = I.channels();

    int nRows = I.rows;
    int nCols = I.cols * channels;

    if (I.isContinuous())
    {
        nCols *= nRows;
        nRows = 1;
    }

    int i,j;
    uchar* p;
    for( i = 0; i < nRows; ++i)
    {
        p = I.ptr<uchar>(i);
        for ( j = 0; j < nCols; ++j)
        {
            p[j] = table[p[j]];
        }
    }
    return I;
}

 

C 语言样式的另一种

The data data member of a Mat object returns the pointer to the first row, first column. If this pointer is null you have no valid input in that object. Checking this is the simplest method to check if your image loading was a success. In case the storage is continues we can use this to go through the whole data pointer.

uchar* p = I.data;

for( unsigned int i =0; i < ncol*nrows; ++i)
    *p++ = table[*p];

The iterator (safe) method

In case of the efficient way making sure that you pass through the right amount of uchar fields and to skip the gaps that may occur between the rows was your responsibility. 指针方式,安全检查由用户自己完成

The iterator method is considered a safer way as it takes over these tasks from the user. All you need to do is ask the begin and the end of the image matrix and then just increase the begin iterator until you reach the end.

 

 

Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() != sizeof(uchar));

    const int channels = I.channels();
    switch(channels)
    {
    case 1:
        {
            MatIterator_<uchar> it, end;
            for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)
                *it = table[*it];
            break;
        }
    case 3:
        {
            MatIterator_<Vec3b> it, end;
            for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)
            {
                (*it)[0] = table[(*it)[0]];
                (*it)[1] = table[(*it)[1]];
                (*it)[2] = table[(*it)[2]];
            }
        }
    }

    return I;
}

On-the-fly address calculation with reference returning

即时的地址计算,引用返回

It was made to acquire or modify somehow random elements in the image. 这种方法不建议用于遍历图像,而是随机访问图像中某个像素

Its basic usage is to specify the row and column number of the item you want to access.

If you need to multiple lookups using this method for an image it may be troublesome and time consuming to enter the type and the at keyword for each of the accesses.

Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() != sizeof(uchar));

    const int channels = I.channels();
    switch(channels)
    {
    case 1:
        {
            for( int i = 0; i < I.rows; ++i)
                for( int j = 0; j < I.cols; ++j )
                    I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
            break;
        }
    case 3:
        {
         Mat_<Vec3b> _I = I;

         for( int i = 0; i < I.rows; ++i)
            for( int j = 0; j < I.cols; ++j )
               {
                   _I(i,j)[0] = table[_I(i,j)[0]];
                   _I(i,j)[1] = table[_I(i,j)[1]];
                   _I(i,j)[2] = table[_I(i,j)[2]];
            }
         I = _I;
         break;
        }
    }

    return I;
}

全部程序如下:

// testOpencv1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <sstream>

using namespace std;
using namespace cv;

static void help()
{
	cout
		<< "\n--------------------------------------------------------------------------" << endl
		<< "This program shows how to scan image objects in OpenCV (cv::Mat). As use case"
		<< " we take an input image and divide the native color palette (255) with the "  << endl
		<< "input. Shows C operator[] method, iterators and at function for on-the-fly item address calculation."<< endl
		<< "Usage:"                                                                       << endl
		<< "./howToScanImages imageNameToUse divideWith [G]"                              << endl
		<< "if you add a G parameter the image is processed in gray scale"                << endl
		<< "--------------------------------------------------------------------------"   << endl
		<< endl;
}

Mat& ScanImageAndReduceC(Mat& I, const uchar* table);
Mat& ScanImageAndReduceIterator(Mat& I, const uchar* table);
Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar * table);

int main( int argc, char* argv[])
{
	help();
	if (argc < 3)
	{
		cout << "Not enough parameters" << endl;
		return -1;
	}

	Mat I, J;
	if( argc == 4 && !strcmp(argv[3],"G") )
		I = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
	else
		I = imread(argv[1], CV_LOAD_IMAGE_COLOR);

	if (!I.data)
	{
		cout << "The image" << argv[1] << " could not be loaded." << endl;
		return -1;
	}

	int divideWith = 0; // convert our input string to number - C++ style
	stringstream s;
	s << argv[2];
	s >> divideWith;
	if (!s || !divideWith)
	{
		cout << "Invalid number entered for dividing. " << endl;
		return -1;
	}

	uchar table[256];
	for (int i = 0; i < 256; ++i)
		table[i] = (uchar)(divideWith * (i/divideWith));

	const int times = 100;
	double t;

	t = (double)getTickCount();

	for (int i = 0; i < times; ++i)
	{
		cv::Mat clone_i = I.clone();
		J = ScanImageAndReduceC(clone_i, table);
	}

	t = 1000*((double)getTickCount() - t)/getTickFrequency();
	t /= times;

	cout << "Time of reducing with the C operator [] (averaged for "
		<< times << " runs): " << t << " milliseconds."<< endl;

	t = (double)getTickCount();

	for (int i = 0; i < times; ++i)
	{
		cv::Mat clone_i = I.clone();
		J = ScanImageAndReduceIterator(clone_i, table);
	}

	t = 1000*((double)getTickCount() - t)/getTickFrequency();
	t /= times;

	cout << "Time of reducing with the iterator (averaged for "
		<< times << " runs): " << t << " milliseconds."<< endl;

	t = (double)getTickCount();

	for (int i = 0; i < times; ++i)
	{
		cv::Mat clone_i = I.clone();
		ScanImageAndReduceRandomAccess(clone_i, table);
	}

	t = 1000*((double)getTickCount() - t)/getTickFrequency();
	t /= times;

	cout << "Time of reducing with the on-the-fly address generation - at function (averaged for "
		<< times << " runs): " << t << " milliseconds."<< endl;

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

	t = (double)getTickCount();

	for (int i = 0; i < times; ++i)
		LUT(I, lookUpTable, J);

	t = 1000*((double)getTickCount() - t)/getTickFrequency();
	t /= times;

	cout << "Time of reducing with the LUT function (averaged for "
		<< times << " runs): " << t << " milliseconds."<< endl;
	return 0;
}

Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
	// accept only char type matrices
	CV_Assert(I.depth() != sizeof(uchar));

	int channels = I.channels();

	int nRows = I.rows;
	int nCols = I.cols * channels;

	if (I.isContinuous())	// 矩阵数据是否连续排列
	{
		nCols *= nRows;
		nRows = 1;
	}

	int i,j;
	uchar* p;
	for( i = 0; i < nRows; ++i)	// 从头到尾
	{
		p = I.ptr<uchar>(i);
		for ( j = 0; j < nCols; ++j)
		{
			p[j] = table[p[j]]; // 将每个像素的映射值重新填回
		}
	}
	return I;
}

Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table)
{
	// accept only char type matrices
	CV_Assert(I.depth() != sizeof(uchar));	// 错误检测 ~~

	const int channels = I.channels();
	switch(channels)
	{
	case 1:
		{
			MatIterator_<uchar> it, end;
			for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)
				*it = table[*it];
			break;
		}
	case 3:
		{
			MatIterator_<Vec3b> it, end;
			for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)
			{
				(*it)[0] = table[(*it)[0]];
				(*it)[1] = table[(*it)[1]];
				(*it)[2] = table[(*it)[2]];
			}
		}
	}

	return I;
}

Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table)
{
	// accept only char type matrices
	CV_Assert(I.depth() != sizeof(uchar));

	const int channels = I.channels();
	switch(channels)
	{
	case 1:
		{
			for( int i = 0; i < I.rows; ++i)
				for( int j = 0; j < I.cols; ++j )
					I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
			break;
		}
	case 3:
		{
			Mat_<Vec3b> _I = I;

			for( int i = 0; i < I.rows; ++i)
				for( int j = 0; j < I.cols; ++j )
				{
					_I(i,j)[0] = table[_I(i,j)[0]];
					_I(i,j)[1] = table[_I(i,j)[1]];
					_I(i,j)[2] = table[_I(i,j)[2]];
				}
				I = _I;
				break;
		}
	}

	return I;
}

OpenCV Tutorials —— Scan images

标签:style   http   io   color   ar   os   使用   sp   for   

原文地址:http://www.cnblogs.com/sprint1989/p/4101502.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!