欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Opencv学习笔记--图像处理的基本操作

程序员文章站 2022-03-05 14:50:15
...

1基本数据类型

图像有若干个通道,灰度图像只有一个通道,而彩色具有红,绿,蓝组成,但是OpenCv以逆序的方式来存储三个分量,还可以使用第四个透明度(alpha),可以使用img.channels()获取图像通道个数。

使用若干个位存储一副图像的每个像素,这被称为图像的深度,灰度图像为8位,即0-255个灰度级,可以用img.depth()获得图像的深度,其返回值为:

CV_8U - 8-bit unsigned integers ( 0..255 ) 
CV_8S - 8-bit signed integers ( -128..127 ) 
CV_16U - 16-bit unsigned integers ( 0..65535 ) 
CV_16S - 16-bit signed integers ( -32768..32767 ) 
CV_32S - 32-bit signed integers ( -2147483648..2147483647 ) 
CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN ) 
CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )

对于灰度图像和彩色图像,最常见的是CV_8U.

Mat img=imread("lena.png",IMREAD_GRAYSCALE);
Mat fp;
img.convertTo(fp,CV_32F);//改变图像的深度
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

2 像素级访问

1. 第一种方法:模板函数at<>

uchar pixel=img.at<uchar>(0,0);  //获得灰度图像0,0点像素
Vec3b pixel=img.at<Vec3B>(0,0);  //获得3波段图像的第一个波段(0,0)像素。
  • 1
  • 2
  • 1
  • 2

第一种方法,效率不高,必须定位到他所在的位置

2. 第二种方法:函数ptr

他返回图像特定行的指针。因此可以得到每一行的数据,时间复杂度降低, 
如下代码获取一副彩色图像的每个像素值。

//时间复杂度大大降低!!!
uchar R,G,B;
for (int i=0;i<img.rows;i++)    //遍历行
    Vec3b pixRow=img.ptr<Vec3b>(i);
for (int j=0;j<img.cols;j++) {   //遍历**列**
    B=pixRow[j][0];
    G=pixRow[j][1];
    R=pixRow[j][2];
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

测量程序用时可用函数:

double to=(double)getTickCount(); 
elapsed=((double)getTickCount()-to)/getTickFrenquency()

图像位运算

可以用掩码对一个图像进行处理,位元算有:

void bitwise_and(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray()) 
其中src1是原始的图像,src2是掩码,dst为输出

一个例子:

#include<opencv2\opencv.hpp>
#include <iostream>  
using namespace cv;
using namespace std;
int main() {
    Mat img = imread("cute.jpg", 1);
    if (img.empty())
        cout << "cannot load image" << endl;
    imshow("Origin", img);
    Mat mask(img.rows, img.cols,CV_8UC3, Scalar(0, 0,0 ));
    circle(mask, Point(img.rows / 2, img.cols / 2-35), 220,Scalar(255,255,255),-1);  //画一个圆
    imshow("Mask", mask);   
    //执行位操作
    Mat r;
    bitwise_and(img, mask, r);
    imshow("Bit_and", r);
    waitKey(0);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

如下所示的图像处理过程: 
分别为原始图像,掩模,计算后的图像 
Opencv学习笔记--图像处理的基本操作 
Opencv学习笔记--图像处理的基本操作 
Opencv学习笔记--图像处理的基本操作

1. Adding (blending) two images using OpenCV

将两张图像以线性组合的方式合并成一张图像,注意的是,两张图像的大小应该相同。 
g(x) = (1 -a )*f0(x) + a*f1(x)g(x)为生成的矩阵,f0(x),f1(x)为要合并的两个矩阵。a为尺度。 
用到的函数原型: 
C++: 
void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1)

#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
        double alpha = 0.5; double beta; double input;
        Mat src1, src2, dst;
        /// Ask the user enter alpha
        std::cout << " Simple Linear Blender " << std::endl;
        std::cout << "-----------------------" << std::endl;
        std::cout << "* Enter alpha [0-1]: ";
        std::cin >> input;
        /// We use the alpha provided by the user if it is between 0 and 1
        if (input >= 0.0 && input <= 1.0)
            alpha = input;
        /// Read image ( same size, same type )
        src1 = imread("LinuxLogo.jpg");
        src2 = imread("WindowsLogo.jpg");
        if (!src1.data) { printf("Error loading src1 \n"); return -1; }
        if (!src2.data) { printf("Error loading src2 \n"); return -1; }
        /// Create Windows
        namedWindow("Linear Blend", 1);
        beta = (1.0 - alpha);
        addWeighted(src1, alpha, src2, beta, 0.0, dst);
        imshow("Linear Blend", dst);
        waitKey(0);
        return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

当a=0时,此时只有window的logo

Opencv学习笔记--图像处理的基本操作

a=0.5时如图所示: 
Opencv学习笔记--图像处理的基本操作

2. Changing the contrast and brightness of an image

改变图像的对比度和亮度 
基础的公式为: 
g(i; j) = a*f(i,j) + b 
where i and j indicates that the pixel is located in the i-th row and j-th column. 
获得一个图片的像素我们用image.at<Vec3b>(y,x)[c] 这里的y为行,x为列,c代表R, G or B (0, 1 or 2)

int main(int argc, char** argv)
{
        double alpha; /**< Simple contrast control */
        int beta; /**< Simple brightness control */
        /// Read image given by user
        Mat image = imread("cute.jpg");
        Mat new_image = Mat::zeros(image.size(), image.type());  //copy the origin picture size,and type
        /// Initialize values
        std::cout << " Basic Linear Transforms " << std::endl;
        std::cout << "-------------------------" << std::endl;
        std::cout << "* Enter the alpha value [1.0-3.0]: "; std::cin >> alpha;
        std::cout << "* Enter the beta value [0-100]: "; std::cin >> beta;
        /// Do the operation new_image(i,j) = alpha*image(i,j) + beta
        for (int y = 0; y < image.rows; y++){
            for (int x = 0; x < image.cols; x++){
                for (int c = 0; c < 3; c++){
                    new_image.at<Vec3b>(y, x)[c] =
                        saturate_cast<uchar>(alpha*(image.at<Vec3b>(y, x)[c]) + beta);//saturate_cast to make sure the values are valid.
                }
            }
        }
        namedWindow("Original Image", 1);
        namedWindow("New Image", 1);
        imshow("Original Image", image);
        imshow("New Image", new_image);
        waitKey();
        return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

示例如下:可以看到改变的图片的对比度和亮度。 
Opencv学习笔记--图像处理的基本操作

这里可以用函数image.convertTo(new_image, -1, alpha, beta);来代替for循环,它会更有效率。

Basic Drawing

1. 定义一个点 2D

Point pt;
pt.x = 10;
pt.y = 8;
Point pt = Point(10, 8);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

2. 画椭圆ellipse原型 
void ellipse(InputOutputArray img, Point center, Size axes, 
double angle, double startAngle, double endAngle, 
const Scalar& color, int thickness = 1, 
int lineType = LINE_8, int shift = 0);

后面三个为默认的参数,可以不写。

//自己写的函数,指定img,和角度
void MyEllipse(Mat img, double angle)
{
    int thickness = 2;
    int lineType = 8;
    ellipse(img,
        Point(w / 2, w / 2),
        Size(w / 4, w / 16),
        angle,
        0,
        360,
        Scalar(255, 0, 0),  //为颜色
        thickness,
        lineType);
}
//**调用方法:**
MyLine(rook_image, Point(0, 15 * w / 16), Point(w, 15 * w / 16));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

3. 画线段

函数原型 
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, 
int thickness = 1, int lineType = LINE_8, int shift = 0);

Random generator and text with OpenCV

随机数产生类Random Number generator class (RNG)

RNG rng( 0xFFFFFFFF );//创建一个RNG类,并对其进行初始化
//在[a,b)中随机产生一个数
C++: int RNG::uniform(int a, int b)
C++: float RNG::uniform(float a, float b)
C++: double RNG::uniform(double a, double b)
//a – lower inclusive boundary of the returned random numbers.
//b – upper non-inclusive boundary of the returned random numbers.
RNG rng;

// always produces 0
double a = rng.uniform(0, 1);

// produces double from [0, 1)
double a1 = rng.uniform((double)0, (double)1);

// produces float from [0, 1)
double b = rng.uniform(0.f, 1.f);

// produces double from [0, 1)
double c = rng.uniform(0., 1.);

// may cause compiler error because of ambiguity:
//  RNG::uniform(0, (int)0.999999)? or RNG::uniform((double)0, 0.99999)?
double d = rng.uniform(0, 0.999999);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Random color

一副彩色图像由R,G,B组成,可用RN*生随机的颜色。

static Scalar randomColor( RNG& rng )
{
int icolor = (unsigned) rng;
return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

Put out the text

获得一个字符串的宽度和高度: 
C++: Size getTextSize(const string& text, int fontFace, double fontScale, int thickness, int* baseLine)
例如: 
Size textsize = getTextSize("OpenCV forever!", CV_FONT_HERSHEY_COMPLEX, 3, 5, 0); 
将其输出: 
C++: void putText(Mat& img, const string& text, Point org, int fontFace, double fontScale, Scalar color, int