首页 > 代码库 > Opencv学习笔记(三)--图像处理的基本操作

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

Opencv图像处理基本操作

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);//改变图像的深度

2 像素级访问

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

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

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

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];
}

测量程序用时可用函数:

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. 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;
}

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

技术分享

a=0.5时如图所示:
技术分享

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;
}

示例如下:可以看到改变的图片的对比度和亮度。
技术分享

这里可以用函数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);

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));

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);

Random color

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

static Scalar randomColor( RNG& rng )
{
int icolor = (unsigned) rng;
return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
}

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 thickness=1, int lineType=8, bool bottomLeftOrigin=false )

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

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