OPENCV学习笔记2-2_图像遍历(使用指针)

  Illustrate(说明) the image-scanning process by accomplishing (完成)a simple task: reducing the number of colors in an image.

 1.1 Principle

  Color images are composed of 3-channel pixels. Since each of these values is an 8-bit unsigned character, the total number of colors is 256x256x256, which is more than 16 million colors. Consequently(因此), to reduce the complexity of an analysis, it is sometimes useful to reduce the number of colors in an image. if you reduce the number of colors in each dimension by 8(8分之1), then you would obtain a total of 32x32x32 colors.

  An image of width W and height H would then require a memory block of WxHx3 uchars. However, for efficiency reasons(性能考虑), the length of a row can be padded with a few extra pixels. This is because some multimedia processor chips  can process images more efficiently when their rows are multiples of 4 or 8. Obviously(当然), these extra pixels are not displayed or saved; their exact values are ignored. OpenCV designates(指定) the length of a padded row as the effective width, the step data attribute(属性) gives you the effective width in number of bytes.

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;

void colorReduce2(Mat &image, int div = 64) {
    int nl = image.rows;                    // number of lines
    int nc = image.cols * image.channels(); // total number of elements per line
    for (int j = 0; j < nl; j++) {
        // get the address of row j
        uchar* data = image.ptr<uchar>(j);
        for (int i = 0; i < nc; i++) {
            //data[i]=120  data[i]/div = 1  1*64=64 64+32=96
            //(80 160 80)(100 200 100)(120 240 120) (96 160 96 )(96 224 96 )(96 224 96 )
            //(1-63->32)(64-127->96)(128-191->160 )         reduce the number of colors
            data[i] = data[i] / div*div + div / 2;

        } // end of line
    }
}

int main()
{
    Mat image = cv::imread("test.jpg", 1);
    resize(image, image, Size(), 0.6, 0.6);
    colorReduce2(image,64);
    namedWindow("YungFung Image");
    imshow("YungFung Image", image);
    waitKey();
    return 0;
}

1.2  Having input and output arguments(参数)

  In our color reduction example, the transformation is directly applied to the input image, which is called an in-place transformation.However, in some applications, the user might(用户可能) want to keep the original image intact(保持原始图像不变). The user would then be forced to create a copy of the image before calling the function. Note that the easiest way to create an identical deep copy of an image is to call the clone method;

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;

//void colorReduce(cv::Mat image, int div = 64) {};
void colorReduce2(const Mat &image,          // input image
                        Mat &result,         // output image
                        int div = 64) {
    int nl = image.rows;
    int nc = image.cols;
    int nchannels = image.channels();

    // allocate output image if necessary
    result.create(image.rows, image.cols, image.type());

    for (int j = 0; j < nl; j++) {
        const uchar* data_in = image.ptr<uchar>(j);
        uchar* data_out = result.ptr<uchar>(j);

        for (int i = 0; i < nc*nchannels; i++) {
            data_out[i] = data_in[i] / div*div + div / 2;
        }
    }
}

int main()
{

    Mat image = imread("test.jpg");
    cv::resize(image, image, cv::Size(), 0.4, 0.4);
    Mat result;

    colorReduce2(image,result);
    cv::namedWindow("YungFung Image");
    cv::imshow("YungFung Image", image);

    cv::namedWindow("Result");
    cv::imshow("Result", result);
    waitKey();
    return 0;
}

1.3 Efficient scanning of continuous images(连续图像的高效扫描)

  A convenient(方便) cv::Mat method can tell us whether the image has been padded or not. This is the isContinuous method that returns true if the image does not include padded pixels. Note that we could also check the continuity of the matrix by writing the following test:

  // check if size of a line (in bytes) equals the number of columns times pixel size in bytes

  image.step == image.cols*image.elemSize();

  To be complete, this test should also check whether the matrix has only one line; in which case(如果是), it is continuous by definition. In some specific processing algorithms(算法), you can take advantage of (利用)the continuity of the image by processing it in one single (longer) loop.

  Note that there is also a reshape method that could have been used here.The reshape method changes the matrix dimensions without requiring any memory copying or reallocation(复制或重新分配内存). The first parameter is the new number of channels and the second one is the new number of rows. The number of columns(列) is readjusted accordingly(相应的).

 

void colorReduce2(cv::Mat &image, int div = 64) {    
    /*
    int nl = image.rows; // number of lines
    int nc = image.cols * image.channels();
    if (image.isContinuous())
    {
        // then no padded pixels
        nc = nc*nl;                        // nc changed
        nl = 1;                            // it is now a long 1D array
    }
    */
    if (image.isContinuous()){
        image.reshape(1, 1);               // new number of channels ,new number of rows
    }
    int nl = image.rows;                   // number of lines
    int nc = image.cols * image.channels();

    // this loop is executed only once in case of continuous images
    for (int j = 0; j < nl; j++) {
        uchar* data = image.ptr<uchar>(j);
        for (int i = 0; i < nc; i++) {
            data[i] = data[i] / div*div + div / 2;
        } 
    }
}

1.4 Low-level pointer arithmetics(低层次指针算法)

  In the cv::Mat class, the image data is contained(存在) in a memory block of unsigned chars(无符号字符块). The address of the first element(元素) of this memory block is given by the data attribute that returns an unsigned char pointer(返回一个无符号指针). So, to start your loop at the beginning of the image, you could have written the following code:

  uchar *data = image.data;

  Moving from one row to the next could have been done by moving your row pointer using the effective width as follows:

  data += image.step; // next line

  The step method gives you the total number of bytes (including the padded pixels) in a line. In general, you can obtain the address of the pixel at row j and column i as follows,However, even if(尽管) this would work in our example, it is not recommended that you proceed this way.

  // address of pixel at (j,i) that is &image.at(j,i)

void colorReduce2(const Mat &image, Mat &result, int div = 64)
{
    int n1 = image.rows;
    int nc = image.cols;
    for (int j = 0; j < n1; j++)
    {
        for (int i = 0; i < nc; i++)
        {
            uchar *data = image.data + j * image.step + i * image.elemSize(); 
            //data_out[i] = data_in[i]/div *div + div/2;  
            data[0] = 0;
            data[1] = 0;
            data[2] = 0;
        }
    }
}

 

转载于:https://www.cnblogs.com/yunfung/p/7553657.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值