遍历opencv中的mat像素的几种方法和概念

2023-05-16

今天在看矩形滤波的时候忽然脑子短路,把一些概念全弄混了,现总结一下,以便下次再混的时候可以参考确认下,自己的理解,有错的地方还请指正。

         首先,在Opencv2中基本上都是用的Mat来表示图像了,C++的函数调用中基本上也都是Mat图,从根本上说,一张图像是一个由数值组成的矩阵,矩阵的每一个元素代表一个像素。对于灰度图像而言,像素有8位无符号数表示,其中0代表黑色,255代表白色。那么矩阵和图像间到底是一个什么样的关系呢。

         第一:Mat图有行和列,即cv::Mat中有公有成员变量cols和rows,注意,这里的cols就是图像的宽度width,rows就是图像的高度height。这个width和height我们可以在其它Opencv的成员中得到,比如矩形Rect,而矩形Rect就是一个经常会用到的结构了,我自己接触到的就包括鼠标选择矩形区域、框住目标的矩形区域、滤波器矩形模版、目标的矩形特征、矩形内的运算等等。可以说Rect是一个非常常用的结构,也是Opencv里非常有用的一个结构,本质上矩形区域就是图像的一个子部分,或者说图像矩阵的一个子矩阵。

         这里我引用《OpenCV学习笔记(四十一)——再看基础数据结构core》中关于Rect的介绍,Rect_类有些意思,成员变量x、y、width、height,分别为左上角点的坐标和矩形的宽和高。常用的成员函数有Size()返回值为一个Size,area()返回矩形的面积,contains(Point)用来判断点是否在矩形内,inside(Rect)函数判断矩形是否在该矩形内,tl()返回左上角点坐标,br()返回右下角点坐标。

         第二:Mat图中的图像像素位置表示和矩阵中元素的表示。这里引用《访问Mat图像中每个像素的值》中几张图来表示Mat矩阵中存数据的关系。单通道灰度图数据存放格式:

                                                                   

多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:

                                             

这时,大家得注意了,二维矩阵的行和列用来表示一个元素,并且一般是从0标号开始,所以实际上是有m+1列,也就是说宽度width是m+1的,行类似。还有就是Mat.at(int y, int x)来访问一个像素,这时候的y表示的行号,x表示的列号,相对应的就是x表示水平的宽,y表示的竖直的高,只不过x和y都是从0开始的标号。容易搞混的地方就在于一些矩阵的相减了,相减完后怎么表示像素位置,这个时候一般比较难把握,但是只要明白矩阵里x,y,width,height的关系,搞清楚就容易多了。

Mat dst;

 int height = dst.rows;
    int width = dst.cols;

for (int i = 0; i < height; i++) {

            for (int j = 0; j < width; j++) {

//假如以十字形遍历索引,则十字中心(i * width + j),上下分别是((i -1)* width + j)((i +1)* width + j)

//左右分别是(i * width + j-1)(i * width + j+1)

//这里的i是代表行数,j代表列数,即所在的行的第几列
                int index = i * width + j;
                //像素值        
                int data = (int)dst.data[index];
                
               }

            }
            

 

 

//=====================================指针法==================================================//

#include<opencv2/opencv.hpp>

#include<iostream>

using namespace std;

using namespace cv;

int main()

{

    Mat img=imread("f:/1.jpg");

    int height=img.rows;

    int width=img.cols;

    for(int i=0;i<height;i++)

    {

        unsigned char *data=img.data+i*width*img.channels();

        for(int j=0;j<width;j++)

        {

            int r=*(data+j*img.channels());

            int g=*(data+j*img.channels()+1);

            int b=*(data+j*img.channels()+2);

            cout<<r<<" "<<g<<" "<<b<<endl;

        }

    }        

    img.release();

    system("pause");

    return 1;

}

//============================================================================================//

推荐使用C++格式,比较方便使用

#include "WangSetup.h"

 

#include <iostream>

#include <cv.h>

#include <highgui.h>

 

using namespace std;

 

int main()

{

    //C++ Format

    cv::Mat img = cv::imread("lena.jpg");

    //取img中(30, 20)这个像素点的bgr信息

    cv::Vec3b bgr = img.at<cv::Vec3b>(30, 20);

    cout << "B: " << (unsigned int)bgr.val[0] << ", ";

    cout << "G: " << (unsigned int)bgr.val[1] << ", ";

    cout << "R: " << (unsigned int)bgr.val[2] << endl;

 

 

    //C Format

    IplImage *img2 = cvLoadImage("lena.jpg");        //8UC3, (0,0)B, (0,0)G, (0,0)R, (0,1)B, ...

    char *ptr = img2->imageData       //图像首地址

        + img2->widthStep * 30        //每行大小 * 行数

        + 3 * 20;                    //BGR占3个大小空间 * 列数

    printf("B: %d, G: %d, R: %d\n", (uchar)ptr[0], (uchar)ptr[1], (uchar)ptr[2]);

    cvReleaseImage(&img2);

     

    return 0;

}

 

 

 

1.用动态地址操作像素:

    Mat srcImage(100, 100, CV_8UC3, Scalar(200,20,100));
 
    imshow("显示图像", srcImage);
 
 
    int rowNumber = srcImage.rows;
    int colNumber = srcImage.cols;
 
 
    for (int i = 0; i < rowNumber; i++)
    {
        for (int j = 0; j < colNumber; j++)
        {
            if (srcImage.at<Vec3b>(i, j)[0] > 180) 
            {
                srcImage.at<Vec3b>(i, j)[0] = 0;            
            }
            
            if (srcImage.at<Vec3b>(i, j)[1] < 50) 
            {
                srcImage.at<Vec3b>(i, j)[1] = 255;
            }
 
            if (srcImage.at<Vec3b>(i, j)[2] < 120) 
            {
                srcImage.at<Vec3b>(i, j)[2] = 0;
            }
 
        }
    }
 
 
    imshow("处理后的图像", srcImage);
cv::mat的成员函数: .at(int y, int x)可以用来存取图像中对应坐标为(x,y)的元素坐标。(Mat类中的cols和rows给出了图像的宽和高。而成员函数at(int x, int y)可以用来存取图像的元素。)由于at方法本身不会对任何数据类型进行转化,故一定要确保指定的数据类型和矩阵中的数据类型相符合。
假设提前已知一幅图像img的数据类型为 unsigned char型灰度图(单通道),对像素的赋值操作为image.at<uchar>(i,j) = value。而对于彩色图像,每个像素由三个部分构成:蓝色通道、绿色通道和红色通道(BGR),对于一个包含彩色图像的Mat,会返回一个由三个8位数组组成的量。OpenCV将此类型定义为Vec3b,即由三个unsigned char组成的向量。这也解释了为什么存取彩色图像像素的代码可以写成:image.at<Vec3b>(i,j)[channel] = value;

以下是统计canndy后的0像素点与255像素点之间的数量的比值:

#define _CRT_SECURE_NO_WARNINGS
 
#include <iostream>
#include <opencv2/opencv.hpp>
 
using namespace std;
using namespace cv;
 
int main() 
{
    Mat graySrc = imread("../../11.bmp", 0);
 
    Mat canImage;
    Canny(graySrc, canImage, 60, 120);
 
    int PicZero = 0;
    int PicFull = 0;
 
    for (int i = 0; i < graySrc.rows; ++i) 
    {
        for (int j = 0; j < graySrc.cols; ++j) 
        {
            if (canImage.at<unsigned char>(i, j) == 0) 
            {
                PicZero++;
            }
            else
            {
                PicFull++;
            }    
        }
    
    }
 
    cout << "0像素点比255像素点的比值为" << (double)PicZero / PicFull << endl;
    system("pause");
}


2.用指针的方法:

有时候我们需要遍历Mat中的每一个像素点,并且对像素点进行处理,这里以图像所有像素点都减去div(div属于int类型)

void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
    // 参数准备
    outputImage = inputImage.clone();
 
    int rowNumber = outputImage.rows;
    int colNumber = outputImage.cols*outputImage.channels();
 
    for (int i = 0; i < rowNumber; i++)
    {
        // 获取第i行的首地址
        uchar* data = outputImage.ptr<uchar>(i);
 
        for (int j = 0; j < colNumber; j++)  // 列循环
        {
            // 开始处理每一个像素值,每一个像素值都减去div
            data[j] = data[j] - div;
        }
    }
}
也可以写成如下形式:

Mat inverseColor1(Mat srcImage) 
{
    Mat tempImage = srcImage.clone();
    int row = tempImage.rows;
    int col = tempImage.cols * tempImage.channels();
 
    for (int i = 0; i < row; ++i) 
    {
        const unsigned char* sourcedata = srcImage.ptr(i);
        unsigned char* data = tempImage.ptr(i);
        for (int j = 0; j < col; j++)
        {
            data[j] = sourcedata[j] - div;
        }
    }
    return tempImage;
}
此时是定义了两个指针类型: const unsigned char*和 unsigned char*,其中const unsigned char* 中的内容只能够被读取,不能被修改。

特别需要注意的是:Mat中每一行元素的个数=列数*通道数


如需要打印M,

    Mat M(3, 2, CV_8UC3, Scalar(0, 0, 255));
    cout << M << endl;
打印结果为:验证了每一行元素的个数为: 列数*通道数

另外需要注意的是:Mat 除了拥有成员变量cols,rows,成员函数channels()之外,还提供了ptr函数可以返回得到图像任意行的首地址。

3.用迭代器Matlterator_:

        Matlterator_是Mat数据操作的迭代器,:begin()表示指向Mat数据的起始迭代器,:end()表示指向Mat数据的终止迭代器。迭代器方法是一种更安全的用来遍历图像的方式,首先获取到数据图像的矩阵起始,再通过递增迭代实现移动数据指针。

Mat inverseColor4(Mat srcImage) 
{
    Mat tempImage = srcImage.clone();
 
    // 初始化原图像迭代器
    MatConstIterator_<Vec3b> srcIterStart = srcImage.begin<Vec3b>();
    MatConstIterator_<Vec3b> srcIterEnd = srcImage.end<Vec3b>();
 
    // 初始化输出图像迭代器
    MatIterator_<Vec3b> resIterStart = tempImage.begin<Vec3b>();
    MatIterator_<Vec3b> resIterEnd = tempImage.end<Vec3b>();
 
    while (srcIterStart != srcIterEnd) 
    {
        (*resIterStart)[0] = 255 - (*srcIterStart)[0];
        (*resIterStart)[1] = 255 - (*srcIterStart)[1];
        (*resIterStart)[2] = 255 - (*srcIterStart)[2];
 
        srcIterStart++;
        resIterStart++;
    }
 
    return tempImage;
 
}

 

 

 

Color Reduce
还是使用经典的Reduce Color的例子,即对图像中的像素表达进行量化。如常见的RGB24图像有256×256×256中颜色,通过Reduce Color将每个通道的像素减少8倍至256/8=32种,则图像只有32×32×32种颜色。假设量化减少的倍数是N,则代码实现时就是简单的value/N*N,通常我们会再加上N/2以得到相邻的N的倍数的中间值,最后图像被量化为(256/N)×(256/N)×(256/N)种颜色。

方法零:.ptr和[]操作符
Mat最直接的访问方法是通过.ptr<>函数得到一行的指针,并用[]操作符访问某一列的像素值。

// using .ptr and []
void colorReduce0(cv::Mat &image, int div=64) {
      int nr= image.rows; // number of rows
      int nc= image.cols * image.channels(); // total number of elements per line
      for (int j=0; j<nr; j++) {
          uchar* data= image.ptr<uchar>(j);
          for (int i=0; i<nc; i++) {
                  data[i]= data[i]/div*div + div/2;
            }                  
      }
}

方法一:.ptr和指针操作
除了[]操作符,我们可以移动指针*++的组合方法访问某一行中所有像素的值。

// using .ptr and * ++ 
void colorReduce1(cv::Mat &image, int div=64) {
      int nr= image.rows; // number of rows
      int nc= image.cols * image.channels(); // total number of elements per line
      for (int j=0; j<nr; j++) {
          uchar* data= image.ptr<uchar>(j);
          for (int i=0; i<nc; i++) {
                 *data++= *data/div*div + div/2;
            } // end of row                 
      }
}

方法二:.ptr、指针操作和取模运算
方法二和方法一的访问方式相同,不同的是color reduce用模运算代替整数除法

// using .ptr and * ++ and modulo
void colorReduce2(cv::Mat &image, int div=64) {
      int nr= image.rows; // number of rows
      int nc= image.cols * image.channels(); // total number of elements per line
      for (int j=0; j<nr; j++) {
          uchar* data= image.ptr<uchar>(j);
          for (int i=0; i<nc; i++) {
                  int v= *data;
                  *data++= v - v%div + div/2;
            } // end of row                 
      }
}

方法三:.ptr、指针运算和位运算
由于进行量化的单元div通常是2的整次方,因此所有的乘法和除法都可以用位运算表示。

// using .ptr and * ++ and bitwise
void colorReduce3(cv::Mat &image, int div=64) {
      int nr= image.rows; // number of rows
      int nc= image.cols * image.channels(); // total number of elements per line
      int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
      // mask used to round the pixel value
      uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
      for (int j=0; j<nr; j++) {
          uchar* data= image.ptr<uchar>(j);
          for (int i=0; i<nc; i++) {
            *data++= *data&mask + div/2;
            } // end of row                 
      }
}

方法四:指针运算
方法四和方法三量化处理的方法相同,不同的是用指针运算代替*++操作。

// direct pointer arithmetic
void colorReduce4(cv::Mat &image, int div=64) {
      int nr= image.rows; // number of rows
      int nc= image.cols * image.channels(); // total number of elements per line
      int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
      int step= image.step; // effective width
      // mask used to round the pixel value
      uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
      // get the pointer to the image buffer
      uchar *data= image.data;
      for (int j=0; j<nr; j++) {
          for (int i=0; i<nc; i++) {
            *(data+i)= *data&mask + div/2;
            } // end of row                 
            data+= step;  // next line
      }
}

方法五:.ptr、*++、位运算以及image.cols * image.channels()
这种方法就是没有计算nc,基本是个充数的方法。

// using .ptr and * ++ and bitwise with image.cols * image.channels()
void colorReduce5(cv::Mat &image, int div=64) {
      int nr= image.rows; // number of rows
      int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
      // mask used to round the pixel value
      uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
      for (int j=0; j<nr; j++) {
          uchar* data= image.ptr<uchar>(j);
          for (int i=0; i<image.cols * image.channels(); i++) {
            *data++= *data&mask + div/2;
            } // end of row                 
      }
}
 

方法六:连续图像
Mat提供了isContinuous()函数用来查看Mat在内存中是不是连续存储,如果是则图片被存储在一行中。

// using .ptr and * ++ and bitwise (continuous)
void colorReduce6(cv::Mat &image, int div=64) {
      int nr= image.rows; // number of rows
      int nc= image.cols * image.channels(); // total number of elements per line
      if (image.isContinuous())  {
          // then no padded pixels
          nc= nc*nr; 
          nr= 1;  // it is now a 1D array
       }
      int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
      // mask used to round the pixel value
      uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
      for (int j=0; j<nr; j++) {
          uchar* data= image.ptr<uchar>(j);
          for (int i=0; i<nc; i++) {
            *data++= *data&mask + div/2;
            } // end of row                 
      }
}

方法七:continuous+channels
与方法六基本相同,也是充数的。

// using .ptr and * ++ and bitwise (continuous+channels)
void colorReduce7(cv::Mat &image, int div=64) {
      int nr= image.rows; // number of rows
      int nc= image.cols ; // number of columns
      if (image.isContinuous())  {
          // then no padded pixels
          nc= nc*nr; 
          nr= 1;  // it is now a 1D array
       }
      int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
      // mask used to round the pixel value
      uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
      for (int j=0; j<nr; j++) {
          uchar* data= image.ptr<uchar>(j);
          for (int i=0; i<nc; i++) {
            *data++= *data&mask + div/2;
            *data++= *data&mask + div/2;
            *data++= *data&mask + div/2;
            } // end of row                 
      }
}

方法八:Mat _iterator
真正有区别的方法来啦,用Mat提供的迭代器代替前面的[]操作符或指针,血统纯正的官方方法~

// using Mat_ iterator 
void colorReduce8(cv::Mat &image, int div=64) {
      // get iterators
      cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();
      cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();
      for ( ; it!= itend; ++it) {
        (*it)[0]= (*it)[0]/div*div + div/2;
        (*it)[1]= (*it)[1]/div*div + div/2;
        (*it)[2]= (*it)[2]/div*div + div/2;
      }
}
 

方法九:Mat_ iterator 和位运算
把方法八中的乘除法换成位运算。

// using Mat_ iterator and bitwise
void colorReduce9(cv::Mat &image, int div=64) {
      // div must be a power of 2
      int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
      // mask used to round the pixel value
      uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
      // get iterators
      cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();
      cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();
      for ( ; it!= itend; ++it) {
        (*it)[0]= (*it)[0]&mask + div/2;
        (*it)[1]= (*it)[1]&mask + div/2;
        (*it)[2]= (*it)[2]&mask + div/2;
      }
}

方法十:MatIterator_
和方法八基本相同。

// using MatIterator_ 
void colorReduce10(cv::Mat &image, int div=64) {
      cv::Mat_<cv::Vec3b> cimage= image;
      cv::Mat_<cv::Vec3b>::iterator it=cimage.begin();
      cv::Mat_<cv::Vec3b>::iterator itend=cimage.end();
      for ( ; it!= itend; it++) { 
        (*it)[0]= (*it)[0]/div*div + div/2;
        (*it)[1]= (*it)[1]/div*div + div/2;
        (*it)[2]= (*it)[2]/div*div + div/2;
      }
}
 

方法十一:图像坐标
// using (j,i)
void colorReduce11(cv::Mat &image, int div=64) {
      int nr= image.rows; // number of rows
      int nc= image.cols; // number of columns
      for (int j=0; j<nr; j++) {
          for (int i=0; i<nc; i++) {
                  image.at<cv::Vec3b>(j,i)[0]=     image.at<cv::Vec3b>(j,i)[0]/div*div + div/2;
                  image.at<cv::Vec3b>(j,i)[1]=     image.at<cv::Vec3b>(j,i)[1]/div*div + div/2;
                  image.at<cv::Vec3b>(j,i)[2]=     image.at<cv::Vec3b>(j,i)[2]/div*div + div/2;
            } // end of row                 
      }
}

方法十二:创建输出图像
之前的方法都是直接修改原图,方法十二新建了输出图像,主要用于后面的时间对比。

// with input/ouput images
void colorReduce12(const cv::Mat &image, // input image 
                 cv::Mat &result,      // output image
                 int div=64) {
      int nr= image.rows; // number of rows
      int nc= image.cols ; // number of columns
      // allocate output image if necessary
      result.create(image.rows,image.cols,image.type());
      // created images have no padded pixels
      nc= nc*nr; 
      nr= 1;  // it is now a 1D array
      int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
      // mask used to round the pixel value
      uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
      for (int j=0; j<nr; j++) {
          uchar* data= result.ptr<uchar>(j);
          const uchar* idata= image.ptr<uchar>(j);
          for (int i=0; i<nc; i++) {
            *data++= (*idata++)&mask + div/2;
            *data++= (*idata++)&mask + div/2;
            *data++= (*idata++)&mask + div/2;
          } // end of row                 
      }
}

方法十三:重载操作符
Mat重载了+&等操作符,可以直接将两个Scalar(B,G,R)数据进行位运算和数学运算。

// using overloaded operators
void colorReduce13(cv::Mat &image, int div=64) {
      int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
      // mask used to round the pixel value
      uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
      // perform color reduction
      image=(image&cv::Scalar(mask,mask,mask))+cv::Scalar(div/2,div/2,div/2);
}

时间对比
通过迭代二十次取平均时间,得到每种方法是运算时间如下。

可以看到,指针*++访问和位运算是最快的方法;而不断的计算image.cols*image.channles()花费了大量重复的时间;另外迭代器访问虽然安全,但性能远低于指针运算;通过图像坐标(j,i)访问时最慢的,使用重载操作符直接运算效率最高。
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

遍历opencv中的mat像素的几种方法和概念 的相关文章

  • C#Socket文件传输(发送与接收代码)

    原文链接 xff1a http www cnblogs com reynoldchan p 3762014 html 这里是发送的代码 xff1a SendVarData是转码后发送函数 1 lt summary gt 2 发送文件 3 l
  • C# Socket服务端与客户端通信(包含大文件的断点传输)

    步骤 xff1a 一 服务端的建立 1 服务端的项目建立以及页面布局 2 各功能按键的事件代码 1 xff09 传输类型说明以及全局变量 2 xff09 Socket通信服务端具体步骤 xff1a xff08 1 xff09 建立一个Soc
  • C# Socket案例(服务端与客户端)

    本文链接 xff1a https blog csdn net qq 42203978 article details 80520299 服务端完整代码 using System using System Net using System N
  • C#中的Socket编程-TCP客户端

    TCP客户端 using System using System Collections Generic using System Linq using System Net using System Net Sockets using S
  • 最小花费(图论算法)

    Description 在n个人中 xff0c 某些人的银行账号之间可以互相转账 这些人之间转账的手续费各不相同 给定这些人之间转账时需要从转账金额里扣除百分之几的手续费 xff0c 请问A最少需要多少钱使得转账后B收到100元 Input
  • C#获取本机IP地址字符串

    1 using System Net 2 using System Net Sockets 3 4 lt summary gt 5 获取本机IP地址 6 lt summary gt 7 lt returns gt 本机IP地址 lt ret
  • C#中Socket通信用法实例详解

    本文实例讲述了C 中Socket通信用法 分享给大家供大家参考 具体如下 xff1a 一 UDP方式 xff1a 服务器端代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  • 内存溢出问题分析

    System OutOfMemoryException 大多是数据处理的过程中 xff0c 对内存资源的管控太过于粗放 建议对于非托管资源的使用不要过于随意 内存分配的时候使用内存池的模式 xff0c 避免内存泄露和内存碎片 你的指针可能成
  • C# GC 垃圾回收机制原理

    转载参照自以下文章 xff1a http www cnblogs com fdyang p 3456258 html c 销毁资源和释放内存 https www cnblogs com Jessy articles 2552839 html
  • c++中 结构体和类的区别

    区别 xff1a 结构是一种用关键字struct声明的自定义数据类型 与类相似 xff0c 也可以包含构造函数 xff0c 常数 xff0c 字段 xff0c 方法 xff0c 属性 xff0c 索引器 xff0c 运算符和嵌套类型等 xf
  • 结构体和类的区别

    结构体和类的区别 xff1a 在做一个项目时 xff0c 使用了较多的结构体 xff0c 并且存在一些结构体的嵌套 xff0c 即某结构体成员集合包含另一个结构体等 xff0c 总是出现一些奇怪的错误 xff0c 才终于下决心好好分析一下到
  • C++程序内存分配方式(堆与栈)

    一 内存布局 1 栈区 xff08 stack xff09 xff1a 由编译器自动分配释放 xff0c 存放函数的参数值 xff0c 局部变量值等 xff0c 其操作方法类似数据结构中的栈 2 堆区 xff08 heap xff09 xf
  • 值引用和引用问题分析

    在c 43 43 中 xff0c 声明一个全局变量A a xff0c 然后在一个局部函数中创建类型A c赋值给a xff0c 对于值类型 xff0c 如结构体等 xff0c 是在栈中分配内存c xff0c 然后拷贝其内存所有值给a xff0
  • vs中寄存器调试窗口可看出程序是多少位运行的及cpu寄存器使用情况

    如果不清楚程序是多少位运行的 xff0c 可在vs中的调试 gt 寄存器调试窗口查看寄存器的寻址位数 xff0c 如果是32位的exe则寄存器寻址显示32位 xff0c 64位的exe则显示64位寻址 1 根据IntPtr Size来判断
  • CentOS6 Squid代理服务器的安装与配置

    一 简介 代理服务器英文全称是Proxy Server xff0c 其功能就是代理网络用户去取得网络信息 Squid是一个缓存Internet 数据的软件 xff0c 其接收用户的下载申请 xff0c 并自动处理所下载的数据 当一个用户想要
  • c++中类型用new和不用new的区别

    解析一 xff1a new创建类对象 xff0c 使用完后需使用delete删除 xff0c 跟申请内存类似 所以 xff0c new有时候又不太适合 xff0c 比如在频繁调用场合 xff0c 使用局部new类对象就不是个好选择 xff0
  • C# Thread开启线程几种方式

    using System using System Collections Generic using System Linq using System Text using System Threading using System Th
  • C#多线程与UI响应 防止界面假死不响应(子线程创建的窗体获取消息响应用Application.DoEvent )

    一 xff0e 概述 在使用C 进行应用程序设计时 xff0c 经常会采用多线程的方式进行一些后台任务的工作 对于不同的应用场景 xff0c 使用的策略也不尽相同 1 后台循环任务 xff0c 少量UI更新 xff1a 例如批量上传文件 x
  • c#中通过截获windows消息禁止改变窗体大小

    private const int WM SYSCOMMAND 61 0x112 private const int MF REMOVE 61 0x1000 private const int SC RESTORE 61 0xF120 还原
  • C#中Monitor和Lock的用法区别

    1 Monitor Enter object 方法是获取锁 xff0c Monitor Exit object 方法是释放锁 xff0c 这就是Monitor最常用的两个方法 xff0c 当然在使用过程中为了避免获取锁之后因为异常 xff0

随机推荐

  • C#数组按值和按引用传递数组区别

    C 中 xff0c 存储数组之类对象的变量并不是实际存储对象本身 xff0c 而是存储对象的引用 按值传递数组时 xff0c 程序将变量传递给方法时 xff0c 被调用方法接受变量的一个副本 xff0c 因此在被调用时试图修改数据变量的值时
  • C#多线程、并发与并行概念

    软件开发 xff0c 网站开发过程中经常有并发 xff0c 并行 这样的多线程 处理与应用 因此 xff0c 有必要对其进行了解与掌握 多线程 xff1a 在了解线程之前 xff0c 要先知道进程这个概念 进程是一个具有独立功能的程序关于某
  • 窗口句柄、窗口类对象的关系

    HWND hwnd xff1b 窗口句柄 CWnd wnd xff1b 窗口类对象 窗口类对象中有一个成员是窗口句柄 窗口句柄 xff0c 提供了窗口的一个标识 xff0c 类似于指针的概念 xff0c 每一个窗口都对应了一个窗口句柄作为其
  • C#对比图片相似度算法

    参考Neal Krawetz博士的这篇文章 实现这种功能的关键技术叫做 34 感知哈希算法 34 Perceptual Hash Algorithm 意思是为图片生成一个指纹 字符串格式 两张图片的指纹越相似 说明两张图片就越相似 但关键是
  • Opencv中Mat图的长、宽、行、列以及图像像素的概念问题

    在Opencv2中基本上都是用的Mat来表示图像了 xff0c C 43 43 的函数调用中基本上也都是Mat图 xff0c 从根本上说 xff0c 一张图像是一个由数值组成的矩阵 xff0c 矩阵的每一个元素代表一个像素 对于灰度图像而言
  • 2023Java最新真实面试题汇总(持续更新)

    一 面经 适当夸夸面试官 xff08 或所在公司 xff09 不会有坏处 如果某个问题完全不会 xff08 或稍微懂点 xff09 xff0c 直接承认 xff08 或略作回答 xff09 并把话题引导向类似话题 xff08 redis集群
  • Windows Media Foundation 音视频采集 小记

    写在前面 我是个讲文明的人 不过有的时候实在忍不住了也要吐槽几句 xff1a 1 我真是跟不上时代 xff0c 到现在了还在研究 Windows 应用开发 咳 xff1b 2 DirectShow 是傻X xff01 我只是想要获取 Cam
  • 关于C++中vector和set使用sort方法进行排序

    C 43 43 中vector和set都是非常方便的容器 xff0c sort方法是algorithm头文件里的一个标准函数 xff0c 能进行高效的排序 xff0c 默认是按元素从小到大排序 将sort方法用到vector和set中能实现
  • C#调用C++(opencv)中图片数据传递的问题

    C 43 43 DLL代码 xff1a C 代码 xff1a 课题需要做一个界面 xff0c 因为某些原因不能用emgucv xff0c 需要在C winform中调用opencv的方法 xff0c 用opencv处理图片之后再传回到C p
  • c#调用c++(Opencv)dll的实例

    c 43 43 代码 MYDLL int GetCenterPos uchar imageData int step int widthValue int heightValue int BinaryThreshold int LineBl
  • OpenCV图像锐化/增强

    OpenCV图像锐化 增强 0 综述 1 Laplacian高通滤波算子 2 Laplacian锐化代码实践 3 USM锐化增强算法 4 USM代码实践 0 综述 图像的卷积计算除了可以完成我们前面介绍的模糊去噪 边缘检测等任务外 xff0
  • OpenCV 图像清晰度评价算法(相机自动对焦)

    相机的自动对焦要求相机根据拍摄环境和场景的变化 xff0c 通过相机内部的微型驱动马达 xff0c 自动调节相机镜头和CCD之间的距离 xff0c 保证像平面正好投影到CCD的成像表面上 这时候物体的成像比较清晰 xff0c 图像细节信息丰
  • 图像清晰度评价15种方法对比

    在无参考图像的质量评价中 xff0c 图像的清晰度是衡量图像质量优劣的重要指标 xff0c 它能够较好的与人的主观感受相对应 xff0c 图像的清晰度不高表现出图像的模糊 本文针对无参考图像质量评价应用 xff0c 对目前几种较为常用的 具
  • opencv系列-图像清晰度评价

    opencv系列 图像清晰度评价 1 xff0c 换了opencv3 4 xff0c 用来测试 2 xff0c opencv好评呀 图像清晰度评价算法有很多种 xff0c 在空域中 xff0c 主要思路是考察图像的领域对比度 xff0c 即
  • 一种新的图像清晰度评价函数,数字图像清晰度评价函数的研究与改进

    摘要 xff1a 摘 要 xff1a 通过分析常见的图像清晰度评价函数 xff0c 针对自动对焦系统中图像清晰度评价问题 xff0c 提出了一种基于聚焦窗口的改进梯度评价函数算法 改进后的算法具有计算量小 实时性好 评价曲线单峰性好 灵敏度
  • 11种图像清晰度评价函数

    典型无参考图像清晰度评价 xff08 可用作对焦评价函数 xff09 Tenengrad评价函数 Tenengrad函数是一种由Tenenbaum提出的 xff0c 基于梯度的常用图像清晰度评价函数 特南梯度 在图像处理中 xff0c 一般
  • TouchGFX界面开发 | C++基础

    C 43 43 基础 TouchGFX是一个基于STM32硬件 xff0c 由C 43 43 写成的软件框架 xff0c 所以有必要对C 43 43 基础有一定的了解 一 C 43 43 新特性 C 语言里 xff0c 变量初始化必须在程序
  • 一种新的图像清晰度评价函数

    自动聚焦是机器人视觉 数字视频系统中的关键技术之 是决定图像质量的重要因素 是获取清晰图 像的第1步 聚焦性能取决于调焦评价函数的准确性和有效性 即评价函数必须具有无偏性好 单峰性强和 较好的抗噪性能 图像模糊的本质是高频分量的损失 聚焦图
  • 遍历Opencv中Mat中每个像素的值

    首先 xff0c 在Opencv2中基本上都是用的Mat来表示图像了 xff0c C 43 43 的函数调用中基本上也都是Mat图 xff0c 从根本上说 xff0c 一张图像是一个由数值组成的矩阵 xff0c 矩阵的每一个元素代表一个像素
  • 遍历opencv中的mat像素的几种方法和概念

    今天在看矩形滤波的时候忽然脑子短路 xff0c 把一些概念全弄混了 xff0c 现总结一下 xff0c 以便下次再混的时候可以参考确认下 xff0c 自己的理解 xff0c 有错的地方还请指正 首先 xff0c 在Opencv2中基本上都是