Brief description of OpenCV functions_Chapter 2 Basic operations of digital images (image reading and writing, image pixel acquisition, image ROI acquisition, image mixing, graphics drawing)

Series Article Directory

  1. Brief description of OpenCV functions_Chapter 1 Basic concepts of digital images (neighborhood, connectivity, color space)
  2. Brief description of OpenCV functions_Chapter 2 Basic operations of digital images (image reading and writing, image pixel acquisition, image ROI acquisition, image mixing, graphics drawing) [this article]
  3. Brief description of OpenCV functions_Chapter 3 Filtering processing of digital images (box, mean, Gaussian, median and bilateral filtering)
  4. Brief description of OpenCV functions_Chapter 4 Morphological processing of digital images and image pyramids. (erosion, dilation, opening and closing operations, morphological gradients, top and black hats, and image pyramids)

Table of contents


foreword

This series of articles is only to record the relevant parameters and simple usage of commonly used OpenCV functions during the process of learning OpenCV, so as to facilitate query and use at any time. The specific algorithm principle will not be introduced too much.
本文C++使用的OpenCV版本是的4.5.5。
python使用的OpenCV版本是4.5.3.56
官方文档参考的是 4.6.0-dev

If you need to find a specific function, you can directly query it from the catalog. The [] symbol is the function name, including codes in C++ and python


Contents of this article :
This article describes how to read and save digital images, how to obtain image pixel values, image ROI acquisition, image mixing methods, and drawing of various graphics. There are both python and C++ code examples above.

References:
1. OpenCV official documentation
2. C++ iterator (STL iterator) iterator detailed explanation
3. Mao Xingyun - Introduction to OpenCV3 programming
4. Blog: OpenCV study notes (fifty-six) - the core of InputArray and OutputArray, Author yang_xian521
5. Blog: When OpenCV creates an image, the meaning of CV_8UC1, CV_32FC3, CV_32S and other parameters, Author: Young__Fan
6. Original article by Captain_zw: [C/C++] size_t detailed explanation


1. Creation and deletion of windows

1.1 Window creation [namedWindow]

namedWindow()
Function:
Create a window for displaying pictures, and then refer to it through a custom window name. If a window with the same name already exists before calling this function, this function will not run.
You can call the destroyWindow or destroyAllWindows function to close the windows that previously occupied memory.
For a simple program, you don't need to close it, because after the program ends, all previous windows will be closed automatically.

Functional form:

C++:
void cv::namedWindow ( const String & winname, int flags = WINDOW_AUTOSIZE)
Python:
cv.namedWindow( winname, flags) -> None

Parameter explanation (take the parameters displayed in C++ as an example):
1.const String& winname: the name of the window
2.int flags = WINDOW_AUTOSIZE: the window display type. Default is WINDOW_AUTOSIZE

flags type explain
WINDOW_NORMAL WINDOW_NORMAL allows the user to change the size of the window and scale the size of the displayed image to match the size of the window.
WINDOW_AUTOSIZE WINDOW_AUTOSIZE will automatically adjust the size of the window to be consistent with the displayed image, and the user cannot manually modify the size of the window.
WINDOW_FREERATIO WINDOW_FREERATIO adjusts the image regardless of image scale.
WINDOW_KEEPRATIO WINDOW_KEEPRATIO adjusts the image while still preserving the image ratio
WINDOW_GUI_NORMAL WINDOW_GUI_NORMAL is the old method of creating a window, which creates a window without a status bar and a toolbar.
WINDOW_GUI_EXPANDED WINDOW_GUI_EXPANDED is a new enhanced GUI. By default: flags == WINDOW_AUTOSIZE| WINDOW_KEEPRATIO| WINDOW_GUI_EXPANDED

Code example:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	Mat img = imread("cat.jpg");
	namedWindow("WINDOW_NORMAL", WINDOW_NORMAL);
	imshow("WINDOW_NORMAL", img);

	namedWindow("WINDOW_AUTOSIZE", WINDOW_AUTOSIZE);
	imshow("WINDOW_AUTOSIZE", img);
	waitKey(0);
	return 0;
}

insert image description here

# PYTHON
import cv2
def main():
    img = cv2.imread("cat.jpg")
    cv2.namedWindow("WINDOW_NORMAL", cv2.WINDOW_NORMAL)
    cv2.imshow("WINDOW_NORMAL", img)

    cv2.namedWindow("WINDOW_AUTOSIZE", cv2.WINDOW_AUTOSIZE)
    cv2.imshow("WINDOW_AUTOSIZE", img)
    cv2.waitKey(0)
if __name__ == "__main__":
    main()

insert image description here

1.2 Deletion of windows [destroyAllWindows / destroyWindow]

destroyAllWindows()
Function:
Close all HighGUI windows.
Functional form:

C++:
void cv::destroyAllWindows()
Python:
cv.destroyAllWindows() -> None

Code example:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	Mat img = imread("cat.jpg");
	namedWindow("WINDOW_NORMAL", WINDOW_NORMAL);
	imshow("WINDOW_NORMAL", img);
	destroyAllWindows();//关闭所有窗口。
	return 0;
}

destroyWindow()
Function:
close the specified window
function form:

C++:
void cv::destroyWindow(const String & winname)
Python:
cv.destroyWindow(winname) ->None

Parameter explanation (take the parameters displayed in C++ as an example):
1.const String & winname: the name of the window.
Code example:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	Mat img = imread("cat.jpg");
	namedWindow("WINDOW_NORMAL", WINDOW_NORMAL);
	imshow("WINDOW_NORMAL", img);
	destroyWindow("WINDOW_NORMAL");//关闭指定的WINDOW_NORMAL窗口
	return 0;
}
# PYTHON
import cv2
def main():
    img = cv2.imread("cat.jpg")
    cv2.namedWindow("WINDOW_NORMAL", cv2.WINDOW_NORMAL)
    cv2.imshow("WINDOW_NORMAL", img)
    cv2.destroyWindow("WINDOW_NORMAL")# 关闭指定的WINDOW_NORMAL窗口
if __name__ == "__main__":
    main()

1.3 Wait function [waitKey]

waitKey()
Function:
Wait for the key to be pressed.
When delay<=0, the function waits for a key press indefinitely, and returns the ASCII code of the key.
When delay>0, wait for delay milliseconds . If the button is pressed halfway, the ASCII code of the button will be returned. If no button is pressed by the end of delay milliseconds, -1 will be returned.

Remark 1:Since the operating system has a minimum time between switching threads, the function does not wait for exact delay milliseconds, but for at least delay milliseconds. To check that a key is pressed without waiting for it, use the pollKey function (refer to the official technical documentation for the pollKey function).

Functional form:

C++:
int cv::waitKey (int delay = 0)
Python:
cv.waitKey(delay) ->retval

Parameter explanation (take the parameters displayed in C++ as an example):
1. delay: int type, indicating the number of delay units in milliseconds. <=0 is a special value, which means infinite waiting.
Code example:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	
	Mat img = imread("cat.jpg");
	namedWindow("WINDOW_NORMAL", WINDOW_NORMAL);
	imshow("WINDOW_NORMAL", img);
	int iOn;
	iOn = waitKey(0);//按下A键
	printf("%d", iOn);
	return 0;
}

insert image description here

# PYTHON
import cv2
def main():
    img = cv2.imread("cat.jpg")
    cv2.namedWindow("WINDOW_NORMAL", cv2.WINDOW_NORMAL)
    cv2.imshow("WINDOW_NORMAL", img)
    iOn = cv2.waitKey(0) #按下A键
    print(iOn)
    cv2.destroyWindow("WINDOW_NORMAL")
    
if __name__ == "__main__":
    main()

insert image description here

2. Image read, write and display

Note: The InputArray type and OutputArray type mentioned in the function below in this article can all be Mat, Mat_, Mat_<T, m, n>, vector, vector<vector>, vector. OutputArray is a derived class of InputArray.

2.1 Image reading [imread]

imread()
Function:
read the image through the specified image reading method, and the general image reading method defaults to IMREAD_COLOR. If the image cannot be read (because of missing files, improper permissions, unsupported or invalid format), the function will return an empty matrix (Mat::data==NULL).

Currently supported file formats are as follows:

  • Windows bitmap: .bmp, .dib
  • JPEG files: .jpeg, .jpg, *.jpe
  • JPEG 2000 file: *.jp2
  • Portable Network Graphics: *.png
  • WebP:*.webp
  • Portable image format: *.pbm, *.pgm, *.ppm, *.pxm, *.pnm
  • PFM file: *.pfm
  • Sun rasters:*.sr, *.ras
  • TIFF files: *.tiff, *.tif
  • OpenEXR image file: *.exr
  • Radiance HDR :*.hdr, *.pic
  • Raster and vector geospatial data supported by GDAL

Precautions

  • This function determines the type of image based on the content, not the file extension.
  • For color images, the decoded image will be stored in BGR order.
  • When using IMREAD_GRAYSCALE, the codec's internal grayscale conversion will be used if available. The result may differ from the output of cvtColor().
  • If EXIF ​​information is embedded in the image file, the EXIF ​​orientation is taken into account, so the image will be rotated accordingly unless the flags IMREAD_IGNORE_ORIENTATION or IMREAD_UNCHANGED are passed in.
  • Use the IMREAD_UNCHANGED flag to preserve floating point values ​​in PFM images. By default, the number of pixels must be less than 2^30.

Functional form:

C++:
Mat cv::imread(const String & filename, int flags = IMREAD_COLOR )
Python:
cv.imread(filename, flags) ->retval

Parameter explanation (take the parameters displayed in C++ as an example):
1. const String & filename: file name (can include path)
2. int flags: the way to read the image, the default is IMREAD_COLOR. You can also use -1, 0, 1:
1 --cv2.IMREAD_COLOR: load BGR image. This is the default flag.
0 - cv2.IMREAD_GRAYSCALE: load image in grayscale mode
-1 - cv2.IMREAD_UNCHANGED: load BGRA image, including alpha channel

All flag types are shown in the following table:

flag explain
IMREAD_UNCHANGED Returns the loaded image as BGRA.
IMREAD_GRAYSCALE Read as a single-band grayscale image.
IMREAD_COLOR Read as 3-band BGR image
IMREAD_ANYDEPTH Returns a 16-bit/32-bit image when the input has the corresponding depth, otherwise converts to an 8-bit image.
IMREAD_ANYCOLOR Images will be read in any possible color format.
IMREAD_LOAD_GDAL Load the image using the gdal driver.
IMREAD_REDUCED_GRAYSCALE_2 If set, always convert the image to a single-channel grayscale image, reducing the image size by 1/2.
IMREAD_REDUCED_COLOR_2 If set, always convert the image to a 3-channel BGR image, reducing the image size by 1/2.
IMREAD_REDUCED_GRAYSCALE_4 If set, always converts the image to a single-channel grayscale image, reducing the image size by 1/4.
IMREAD_REDUCED_COLOR_4 If set, always convert the image to a 3-channel BGR image, reducing the image size by 1/4.
IMREAD_REDUCED_GRAYSCALE_8 If set, always converts the image to a single-channel grayscale image, reducing the image size by 1/8.
IMREAD_REDUCED_COLOR_8 If set, always converts the image to a 3-channel BGR image, reducing the image size by 1/8.
IMREAD_IGNORE_ORIENTATION If set, do not rotate images according to EXIF's orientation flag.

Code example:

//C++
#include<opencv2/opencv.hpp>

using namespace cv;

int main() {
    
    
	Mat img = imread("cat.jpg", 1);
	namedWindow("BGR");
	imshow("BGR", img);

	img = imread("cat.jpg", 0);
	namedWindow("GRAY");
	imshow("GRAY", img);
	waitKey(0);
	return 0;
}

insert image description here
The running result of python is consistent with that of C++

# PYTHON
import cv2
def main():
    img = cv2.imread("cat.jpg", 1)
    cv2.namedWindow("BGR")
    cv2.imshow("BGR", img)

    img = cv2.imread("cat.jpg", 0)
    cv2.namedWindow("GRAY")
    cv2.imshow("GRAY", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
if __name__ == "__main__":
    main()

2.2 Image display [imshow]

imshow()
Function:
display the image in the specified window. If no window has been created before this function, one with cv::WINDOW_AUTOSIZE is assumed to be created.

The imshow function is used to display an image in a specified window. If the window was created with the cv::WINDOW_AUTOSIZE flag, the image is displayed at its original size, but it is still limited by the screen resolution. Otherwise, the image will be scaled to fit the window. This function can scale the image according to the depth:

  • If the image is 8-bit unsigned, it is displayed as-is.
  • If the image is 16-bit unsigned, the pixels are divided by 256. That is, the value range of [0,255*256] is mapped to [0,255].
  • If the image is 32-bit or 64-bit floating point, the pixel values ​​are multiplied by 255. That is, the value range [0,1] is mapped to [0,255].
  • 32-bit integer images are no longer handled due to the ambiguity of the required transform. Convert to 8-bit unsigned matrix using custom preprocessing specific to the image context.
    Note: When displaying images, waitkey() is used together, otherwise it cannot be displayed for a long time

Functional form:

C++:
void cv::imshow(const String & winname, InputArray mat )
Python:
cv.imshow( winname, mat ) -> None

Parameter explanation (take the parameters displayed in C++ as an example):

1. const String & winname: window name
2. InputArray mat: image data.

Code example:
see example above

2.3 Image writing [imwrite]

imwrite()
Function:
Save the input data according to the specified path, name and save method.

Functional form:

C++:
bool cv::imwrite(const String & filename, InputArray img, const std::vector< int > & params = std::vector< int >() )
Python:
cv.imwrite(filename, img[, params]) -> retval

Parameter explanation (take the parameters displayed in C++ as an example):
1. const String & filename: the name of the saved image, with a suffix.
2.InputArray img: image data.
3 const std::vector<int> & params : Indicates the parameter encoding saved in a specific format, exists in pairs (paramId_1, paramValue_1, paramId_2, paramValue_2, ... .) See cv::ImwriteFlags. When it is not set, the default value is vector<int>(), and it is generally not necessary to fill in.

The following is the parameter table of imwriteFlags, machine-translated. If not clear refer to cv::ImwriteFlags

Imwriteflags flag content
IMWRITE_JPEG_QUALITY For JPEG, the quality can be from 0 to 100 (higher is better). The default value is 95.
IMWRITE_JPEG_PROGRESSIVE Enable JPEG feature, 0 or 1, default is False.
IMWRITE_JPEG_OPTIMIZE Enable JPEG feature, 0 or 1, default is False.
IMWRITE_JPEG_RST_INTERVAL JPEG restart interval, 0—65535, the default is 0—do not restart.
IMWRITE_JPEG_LUMA_QUALITY Individual brightness quality level, 0 - 100, default -1 - not used.
IMWRITE_JPEG_CHROMA_QUALITY Separation chroma quality level, 0 - 100, default -1 - not used.
IMWRITE_JPEG_SAMPLING_FACTOR For JPEG, sets the sampling factor.
IMWRITE_PNG_COMPRESSION For PNG, it can be a compression level from 0 to 9. The higher the value, the longer the compression time and the smaller the file size. If specified, the strategy will be changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). The default is 1 (best speed setting).
IMWRITE_PNG_STRATEGY One of cv::ImwritePNGFlags, defaults to IMWRITE_PNG_STRATEGY_RLE.
IMWRITE_PNG_BILEVEL binary png image, 0 or 1, the default is 0
IMWRITE_PXM_BINARY It can be a binary format flag, 0 or 1, for PPM, PGM or PBM. The default value is 1.
IMWRITE_EXR_TYPE
IMWRITE_EXR_COMPRESSION EXR storage type (default is FLOAT (FP32))
IMWRITE_WEBP_QUALITY Override EXR compression type (ZIP_COMPRESSION = 3 is default) for WEBP, quality can be from 1 to 100 (higher is better). By default (without any arguments), lossless compression is used for qualities over 100.
IMWRITE_PAM_TUPLETYPE For PAM, set the TUPLETYPE field to the appropriate string value defined for that format.
IMWRITE_TIFF_RESUNIT For TIFF, used to specify which DPI resolution unit to set; see libtiff documentation for valid values.
IMWRITE_TIFF_XDPI For TIFF, use to specify the X-direction DPI. For the concept of DPI, please refer to the brief description of the OpenCV function in the previous chapter_Chapter 1 The basic concepts of digital images (neighborhood, connectivity, color space) explanation
IMWRITE_TIFF_YDPI For TIFF, use to specify the Y direction DPI.
IMWRITE_TIFF_COMPRESSION 对于TIFF,使用来指定图像压缩方案。有关与压缩格式对应的整型常量,请参阅libtiff。注意,对于深度为CV_32F的图像,只使用libtiff的SGILOG压缩方案。对于其他支持深度,压缩方案可以由该标志指定;LZW压缩是默认值。
IMWRITE_JPEG2000_COMPRESSION_X1000 对于JPEG2000,使用来指定目标压缩率(乘以1000)。取值为0 ~ 1000。默认是1000。

代码示例:

enum ImwriteFlags {
IMWRITE_JPEG_QUALITY = 1,
IMWRITE_JPEG_PROGRESSIVE = 2,
IMWRITE_JPEG_OPTIMIZE = 3,
IMWRITE_JPEG_RST_INTERVAL = 4,
IMWRITE_JPEG_LUMA_QUALITY = 5,
IMWRITE_JPEG_CHROMA_QUALITY = 6,
IMWRITE_PNG_COMPRESSION = 16
IMWRITE_PNG_STRATEGY = 17,
IMWRITE_PNG_BILEVEL = 18,0.
IMWRITE_PXM_BINARY = 32,
IMWRITE_EXR_TYPE = (3 << 4) + 0,
IMWRITE_EXR_COMPRESSION = (3 << 4) + 1,
IMWRITE_WEBP_QUALITY = 64,
IMWRITE_PAM_TUPLETYPE = 128,
IMWRITE_TIFF_RESUNIT = 256,
IMWRITE_TIFF_XDPI = 257,
IMWRITE_TIFF_YDPI = 258,
IMWRITE_TIFF_COMPRESSION = 259,
IMWRITE_JPEG2000_COMPRESSION_X1000 = 272 };

//C++
//以IMWRITE_PNG_COMPRESSION 为例。 IMWRITE_PNG_COMPRESSION 的对应值为16
#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;

int main() {
    
    
	Mat img = imread("cat.jpg", 1);
	vector<int>flag1 = {
    
    16, 0};
	vector<int>flag2 = {
    
    16, 9};

	imwrite("cat.png", img);
	imwrite("cat1.png", img, flag1);
	imwrite("cat2.png", img, flag2);
	return 0;
}

insert image description here
python结果同上

# PYTHON
import cv2
def main():
    img = cv2.imread("cat.jpg")
    cv2.imwrite("cat.png", img)
    cv2.imwrite("cat1.png", img, (16, 0))
    cv2.imwrite("cat2.png", img, (16, 9))
if __name__ == "__main__":
    main()

3. 图像像素值的获取和修改

3.1 C++获取Mat类型图像像素值并修改

补充知识:
1.Mat类由两部分组成,分别是矩阵头(包含矩阵的尺寸、存储方法、存储地址等信息)和一个指向存储所有像素的矩阵的指针。
2.通常Mat类的复制,例如拷贝构造函数,都仅是复制矩阵头,不复制矩阵。如果要复制矩阵数据则需要函数clone()和函数copyTo()。具体方法本处不做过多解释。
3.值得注意的是Mat数据存储的方式是依次存储每个位置上所有通道像素数后再存储下一个。因此它的尺度为(rows × \times ×(col*channels))

3.1.1 指针访问[ptr]

ptr是Mat的成员函数,可以获取指定行数的数据首地址。

//C++
#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;
int main() {
    
    
	Mat img = imread("cat.jpg");
	Mat changeImg;
	//复制矩阵数据
	img.copyTo(changeImg);

	for (int row = 0; row < changeImg.rows; row++) {
    
    
		// ptr函数可以得到任意行的首地址
		uchar* data = changeImg.ptr<uchar>(row);
		// mat类型存储数据的形式是row * (col*channls)
		for (int col = 0; col < changeImg.cols * changeImg.channels(); col++) {
    
    
			//修改像素值,降低对比度
			data[col] = data[col] / 2;
		}	
	}
	namedWindow("BGR", WINDOW_AUTOSIZE);
	namedWindow("BGR_change", WINDOW_AUTOSIZE);
	imshow("BGR", img);
	imshow("BGR_change", changeImg);
	waitKey(0);
	return 0;
}

insert image description here

3.1.2 迭代器[iterator]

STL迭代器 iterator

定义:容器类名::iterator 迭代器名

要访问顺序容器和关联容器中的元素,需要通过“迭代器(iterator)”进行。迭代器是一个变量,相当于容器和操纵容器的算法之间的中介。迭代器可以指向容器中的某个元素,通过迭代器就可以读写它指向的元素。从这一点上看,迭代器和指针类似。

通过迭代器可以读取它指向的元素,*迭代器名就表示迭代器指向的元素。通过非常量迭代器还能修改其指向的元素。

迭代器都可以进行++操作。反向迭代器和正向迭代器的区别在于:

  • 对正向迭代器进行++操作时,迭代器会指向容器中的后一个元素;
  • 而对反向迭代器进行++操作时,迭代器会指向容器中的前一个元素。

更多细节请参考C++迭代器(STL迭代器)iterator详解

//C++
#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;
int main() {
    
    
	Mat img = imread("cat.jpg");
	Mat changeImg;
	img.copyTo(changeImg);
	//定义迭代器, Vec3b表示Vec<uchar, 3>
	Mat_<Vec3b>::iterator it = changeImg.begin<Vec3b>();//开始位置
	Mat_<Vec3b>::iterator itend = changeImg.end<Vec3b>();//结束位置
	for (;it!=itend; it++) {
    
    
		//降低对比度
		(*it)[0] = (*it)[0]/2;
		(*it)[1] = (*it)[1]/2;
		(*it)[2] = (*it)[2]/2;
	}
	namedWindow("BGR", WINDOW_AUTOSIZE);
	namedWindow("BGR_change", WINDOW_AUTOSIZE);
	imshow("BGR", img);
	imshow("BGR_change", changeImg);
	waitKey(0);
	return 0;
}

3.1.3 动态地址计算[at]

Mat at()
作用
template< typename _Tp> inline
Tp& Mat::at(int i0, int i1)
参数形式
1.int i0:Mat类型的行。
2.int i1:Mat类型的列。
3. return Tp类型的数据。
类型有:

类型
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;
typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
typedef Vec<ushort, 2> Vec2w;
typedef Vec<ushort, 3> Vec3w;
typedef Vec<ushort, 4> Vec4w;
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<int, 6> Vec6i;
typedef Vec<int, 8> Vec8i;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;

代码【结果同上】

//C++
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main() {
    
    
	Mat img = imread("cat.jpg");
	Mat changeImg;
	img.copyTo(changeImg);

	for (int row = 0; row < changeImg.rows; row++) {
    
    
		for (int col = 0; col < changeImg.cols; col++) {
    
    
			//修改像素值,降低对比度
			changeImg.at<Vec3b>(row, col)[0] = changeImg.at<Vec3b>(row, col)[0] / 2;
			changeImg.at<Vec3b>(row, col)[1] = changeImg.at<Vec3b>(row, col)[1] / 2;
			changeImg.at<Vec3b>(row, col)[2] = changeImg.at<Vec3b>(row, col)[2] / 2;
		}	
	}
	namedWindow("BGR", WINDOW_AUTOSIZE);
	namedWindow("BGR_change", WINDOW_AUTOSIZE);
	imshow("BGR", img);
	imshow("BGR_change", changeImg);
	waitKey(0);
	return 0;
}

3.2 python获取numpy类型图像像素值并修改

# PYTHON
import cv2
import copy
def main():
    img = cv2.imread("cat.jpg")
    rows = img.shape[0]
    cols = img.shape[1]
    img2 = copy.deepcopy(img)
    for row in range(rows):
        for col in range(cols):
            img2[row, col] = img2[row, col] + 20
    #或者直接相加 img2 = img2 + 20
    cv2.namedWindow("changeImg", cv2.WINDOW_AUTOSIZE)
    cv2.imshow("changeImg", img2)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

注意:python中使用img2 = img2 + 20可以对所有通道的像素增加20,而Mat类型的图像数据如果进行img2 = img2 + 20则只对第一个通道(Blue)增加20

4 图像特征的获取(行,列,通道数,数据类型,像素的数目)

# PYTHON
import cv2
import copy

def main():
    img = cv2.imread("cat.jpg")
    # shape是tuple类型的数据
    # 其中shape[0]是行数,shape[1]是列数,shape[2]是通道数
    print(img.shape)
    #获取像素的数目,shape[0]*shape[1]*shape[2]
    print(img.size)
    #获取图像数据类型
    print(img.dtype)

if __name__ == "__main__":
    main()

insert image description here

C++版本

//C++
#include<opencv2/opencv.hpp>
#include<iostream>
#include<typeinfo>
using namespace std;
using namespace cv;

int main() {
    
    

	Mat img = imread("cat.jpg");
	cout << "图像行数" << img.rows << endl;
	cout << "图像列数" << img.cols << endl;
	cout << "图像通道数" << img.channels() << endl;
	cout << "图像像素的数目" << img.size[0]* img.size[1] * img.channels()<< endl;
	cout << "图像的类型" << typeid(img).name() << endl;
	cout << "图像像素的类型" << typeid(img.data).name() << endl;
	return 0;
}

insert image description here

5 图像感兴趣区域的获取(Rect/Range)

5.1 Rect获取感兴趣区域[Rect]

Rect类
作用:
类函数,包含四个成员变量。分别存储图像左上角的坐标和宽高。
函数形式:

C++:
template
cv::Rect_< Tp >::Rect (_Tp _x, _Tp _y, _Tp _width, _Tp _height )

参数解释(以C++展示的参数为例):
注意横轴为x轴,竖轴为y轴,横轴表示宽度,竖轴表示高度。对应前面图像的rows变量对应此处为y轴,cols变量对应此处为x轴,注意区分。
1._Tp _x:_Tp类型的_x,表示图像左上角x坐标
2._Tp _y:_Tp类型的_y,表示图像左上角y坐标
3. _Tp _width:_Tp类型的_width,表示图像x轴的宽度
4. _Tp _height:_Tp类型的_height,表示图像x轴的高度
代码示例:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;

int main() {
    
    
	Mat img = imread("cat.jpg");

	Mat roiImg = img(Rect(100, 300, 200, 300));

	namedWindow("BGR", WINDOW_AUTOSIZE);
	namedWindow("Roi", WINDOW_AUTOSIZE);
	imshow("BGR", img);
	imshow("Roi", roiImg);
	waitKey(0);
	return 0;
}

insert image description here

注意和C++ Rect的参数进行区别,python始终保持竖轴为x轴,表示高度,横轴为y轴,表示宽度,Rect竖轴为y轴,表示高度,横轴为x轴,表示宽度

# PYTHON
import cv2
import copy
def main():
    img = cv2.imread("cat.jpg")
    roiImg = copy.deepcopy(img[300:300+300, 100:100+200, :])

    cv2.namedWindow("BGR", cv2.WINDOW_AUTOSIZE)
    cv2.imshow("BGR", img)
    cv2.namedWindow("python_Roi", cv2.WINDOW_AUTOSIZE)
    cv2.imshow("python_Roi", roiImg)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

insert image description here

5.2 Range获取感兴趣区域[Range]

Range类
作用:
一个类函数,可以保存开始坐标和结束坐标。
函数形式:

C++:
Range (int _start, int _end)
参数解释(以C++展示的参数为例):
1.int _start:int类型的start变量,表示开始坐标。
2.int _end: int类型的end变量,表示结束坐标。
代码示例:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	Mat img = imread("cat.jpg");
	//此时就和上例python类似,分别对图像row和col进行获取。
	//第一个参数获取row,第二个参数获取col。
	Mat roiImg = img(Range(300,300+300), Range(100, 100 + 200));
	namedWindow("BGR", WINDOW_AUTOSIZE);
	namedWindow("Roi", WINDOW_AUTOSIZE);
	imshow("BGR", img);
	imshow("Roi", roiImg);
	waitKey(0);
	return 0;
}

insert image description here

6 分解、合并图像通道

6.1 分解图像通道[split]

split()
作用:
将多通道数据划分为几个单通道数据。
函数形式:

C++:
void cv::split (const Mat & src, Mat* mvbegin)
Python:
cv.split(m[, mv]) -> mv

参数解释(以C++展示的参数为例):
1.const Mat & src:表示原始多通道图像数据。
2.Mat* mvbegin:输出数组;数组的数量必须匹配src.channels()。

代码示例:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	Mat img = imread("cat.jpg");
	Mat channel[3];
	split(img, channel);
	namedWindow("BGR", WINDOW_NORMAL);
	namedWindow("B", WINDOW_NORMAL);
	namedWindow("G", WINDOW_NORMAL);
	namedWindow("A", WINDOW_NORMAL);
	imshow("BGR", img);
	imshow("B", channel[0]);
	imshow("G", channel[0]);
	imshow("A", channel[0]);
	waitKey(0);
	return 0;
}

insert image description here

#PYTHON
import cv2

def main():
    img = cv2.imread("cat.jpg")
    B, G, A = cv2.split(img)
    cv2.namedWindow("BGR", cv2.WINDOW_NORMAL)
    cv2.imshow("BGR", img)
    cv2.namedWindow("B_python", cv2.WINDOW_NORMAL)
    cv2.imshow("B_python", B)
    cv2.namedWindow("G_python", cv2.WINDOW_NORMAL)
    cv2.imshow("G_python", B)
    cv2.namedWindow("R_python", cv2.WINDOW_NORMAL)
    cv2.imshow("R_python", B)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

insert image description here

6.2 合并图像通道[merge]

merge()
作用:
将多个同类型,同大小,同深度的单通道数据,合并成多通道数据。
函数形式:

C++:
void cv::merge (const Mat * mv, size_t count, OutputArray dst )
Python:
cv.merge( mv[, dst] ) -> dst

引用自博主Captain_zw的原创文章:【C/C++】size_t详解
size_t简单理解为 unsigned int就可以了,64位系统中为 long unsigned int。具体细节可以取该播主的文章中了解。

参数解释(以C++展示的参数为例):

  1. const Mat * mv: 表示待合并矩阵的输入数组,mv中的所有矩阵必须具有相同的大小和相同的深度。
  2. size_t count:表示输入矩阵的个数,它必须大于零。
  3. OutputArray dst :输出数组的大小和深度与mv[0]相同,通道的数量将等于参数计数。

代码示例:

// C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	Mat img = imread("cat.jpg");
	Mat channel[3];
	split(img, channel);
	Mat channl_RGB[3] = {
    
    channel[2], channel[1], channel[0]};

	Mat dst;
	merge(channl_RGB, 3, dst);
	namedWindow("merge_RGB", WINDOW_AUTOSIZE);
	imshow("merge_RGB", dst);
	waitKey(0);
	return 0;
}

insert image description here

# PYTHON
import cv2
def main():
    img = cv2.imread("cat.jpg")
    B, G, R = cv2.split(img)
    RGB_img = cv2.merge((R, G, B))
    cv2.namedWindow("RGB", cv2.WINDOW_AUTOSIZE)
    cv2.imshow("RGB", RGB_img)
    cv2.waitKey(0)
	#显示结果同上
if __name__ == "__main__":
    main()

7 图像混合[addWeighted]

addWeighted()
作用:
计算两个数组的加权和。
addWeighted函数计算两个数组的加权和如下所示:
d s t [ I ] = α ∗ s r c 1 [ I ] + β ∗ s r c 2 [ I ] + γ dst[I] =\alpha*src1[I]+\beta*src2[I]+\gamma dst[I]=αsrc1[I]+βsrc2[I]+γ
其中I是数组元素的多维索引。在多通道阵列的情况下,每个通道都独立处理。
当输出数组的深度为CV_32S时。就会存在内存溢出情况,甚至可能得到一个错误的符号的结果。

函数形式:

C++:
void cv::addWeighted (InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype = -1)
Python:
cv.addWeighted( src1, alpha, src2, beta, gamma[, dst[, dtype]] ) -> dst

参数解释(以C++展示的参数为例):
1.InputArray src1:Src1第一个输入数组。
2.double alpha: 第一个数组元素的权值。
3.InputArray src2:Src2第二个输入数组,其大小和通道号与src1相同。
4.double beta:第二个数组元素的权重。
5.double gamma:一个加到权重总和上的标量值。
6.OutputArray dst: 输出数组dst,具有与输入数组相同的大小和通道数量。
7.int dtype:输出数组可选深度。当两个输入数组具有相同的深度时,dtype可以设置为-1,这相当于src1.depth()。depth函数可参考官方文档
代码示例:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	Mat img = imread("cat.jpg");
	Mat logo = imread("sunKnight.jpg");
	Mat RoiImg = img(Range(100, 100 + logo.rows), Range(500, 500 + logo.cols));
	// RoiImg 所指向的矩阵数据任然是img,因此修改RoiImg,就是在修改img数据
	addWeighted(RoiImg, 0.1, logo, 0.5, 0, RoiImg);
	namedWindow("mix", WINDOW_AUTOSIZE);
	imshow("mix", img);
	namedWindow("logo", WINDOW_AUTOSIZE);
	imshow("logo", logo);

	waitKey(0);
	return 0;
}

注意:RoiImg 只是修改了矩阵头,所指向的矩阵数据任然是img。因此修改RoiImg,就是在修改img数据。如果需要复制数据,则需要借助clone函数和copyTo函数
insert image description here

# PYTHON
import cv2

def main():
    img = cv2.imread("cat.jpg")
    logo = cv2.imread("sunKnight.jpg")
    img[300:300 + logo.shape[0], 600:600 + logo.shape[1]] \
        = cv2.addWeighted(img[300:300 + logo.shape[0], 600:600 + logo.shape[1]], 0.1, logo, 0.5, 0)
    cv2.namedWindow("mix_python", cv2.WINDOW_AUTOSIZE)
    cv2.imshow("mix_python", img)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

insert image description here

8.色彩变换[cvtColor]

cvtColor()
作用:
将图像从一种颜色空间转换为另一种颜色空间。

注意,OpenCV中默认的颜色格式通常被称为RGB,但它实际上是BGR(字节颠倒)

R、G和B通道值的常规范围为:

  • CV_8U图像0到255
  • CV_16U图像0到65535
  • 0到1 CV_32F图像

函数形式:

C++:
void cv::cvtColor (InputArray src, OutputArray dst, int code, int dstCn = 0)
Python:
cv.cvtColor( src, code[, dst[, dstCn]] ) -> dst

参数解释(以C++展示的参数为例):
1.InputArray src:src输入图像:8位unsigned, 16位unsigned (CV_16UC…),或单精度浮点。
2.OutputArray dst:dst输出与src相同大小和深度的图像。
3.int code:颜色空间转换标志。
4.int dstCn = 0:目标图像中的通道数;如果该参数为0,则通道的数量将自动从src和代码中继承。

code类型
RGB和BGR(opencv默认的彩色图像的颜色空间是BGR)颜色空间的转换 cv::COLOR_BGR2RGB
cv::COLOR_RGB2BGR
cv::COLOR_RGBA2BGRA
cv::COLOR_BGRA2RGBA
向RGB和BGR图像中增添alpha通道 cv::COLOR_RGB2RGBA
cv::COLOR_BGR2BGRA
从RGB和BGR图像中去除alpha通道 cv::COLOR_RGBA2RGB
cv::COLOR_BGRA2BGR
从RBG和BGR颜色空间转换到灰度空间 cv::COLOR_RGB2GRAY
cv::COLOR_BGR2GRAY
cv::COLOR_RGBA2GRAY
cv::COLOR_BGRA2GRAY
从灰度空间转换到RGB和BGR颜色空间 cv::COLOR_GRAY2RGB
cv::COLOR_GRAY2BGR
cv::COLOR_GRAY2RGBA
cv::COLOR_GRAY2BGRA
RGB和BGR颜色空间与BGR565颜色空间之间的转换 cv::COLOR_RGB2BGR565
cv::COLOR_BGR2BGR565
cv::COLOR_BGR5652RGB
cv::COLOR_BGR5652BGR
cv::COLOR_RGBA2BGR565
cv::COLOR_BGRA2BGR565
cv::COLOR_BGR5652RGBA
cv::COLOR_BGR5652BGRA
灰度空间域BGR565之间的转换 cv::COLOR_GRAY2BGR555
cv::COLOR_BGR5552GRAY
RGB和BGR颜色空间与CIE XYZ之间的转换 cv::COLOR_RGB2XYZ
cv::COLOR_BGR2XYZ
cv::COLOR_XYZ2RGB
cv::COLOR_XYZ2BGR
RGB和BGR颜色空间与uma色度(YCrCb空间)之间的转换 cv::COLOR_RGB2YCrCb
cv::COLOR_BGR2YCrCb
cv::COLOR_YCrCb2RGB
cv::COLOR_YCrCb2BGR
RGB和BGR颜色空间与HSV颜色空间之间的相互转换 cv::COLOR_RGB2HSV
cv::COLOR_BGR2HSV
cv::COLOR_HSV2RGB
cv::COLOR_HSV2BGR
RGB和BGR颜色空间与HLS颜色空间之间的相互转换 cv::COLOR_RGB2HLS
cv::COLOR_BGR2HLS
cv::COLOR_HLS2RGB
cv::COLOR_HLS2BGR
RGB和BGR颜色空间与CIE Lab颜色空间之间的相互转换 cv::COLOR_RGB2Lab
cv::COLOR_BGR2Lab
cv::COLOR_Lab2RGB
cv::COLOR_Lab2BGR
RGB和BGR颜色空间与CIE Luv颜色空间之间的相互转换 cv::COLOR_RGB2Luv
cv::COLOR_BGR2Luv
cv::COLOR_Luv2RGB
cv::COLOR_Luv2BGR
Bayer格式(raw data)向RGB或BGR颜色空间的转换 cv::COLOR_BayerBG2RGB
cv::COLOR_BayerGB2RGB
cv::COLOR_BayerRG2RGB
cv::COLOR_BayerGR2RGB
cv::COLOR_BayerBG2BGR
cv::COLOR_BayerGB2BGR
cv::COLOR_BayerRG2BGR
cv::COLOR_BayerGR2BGR

代码示例:
代码参考上一章OpenCV函数简记_第一章数字图像的基本概念(邻域,连通,色彩空间) 中的1.5.6 色彩空间示例章节。

9 缩放函数[resize]

resize()
作用:
对目标图像缩放到指定尺寸。
函数形式:

C++:
resize()
void cv::resize (InputArray src, OutputArray dst, Size dsize, double fx = 0, double fy = 0,
int interpolation = INTER_LINEAR)
Python:
cv.resize( src, dsize[, dst[, fx[, fy[, interpolation]]]] ) -> dst

参数解释(以C++展示的参数为例):
1.InputArray src:输入图像
2.OutputArray dst:输出图像
3.Size dsize:输出图像的尺度大小。Size类是先宽度,后高度来构造对象的。Size_ (_Tp _width, _Tp _height)
4.double fx :横轴上的比例因子;当它等于0时,它被计算为 ( d o u b l e ) d s z i e . w i d t h / s r c . c o l s (double)dszie.width/src.cols (double)dszie.width/src.cols
5.double fy:竖轴上的比例因子;当它等于0时,它被计算为 ( d o u b l e ) d s z i e . h e i g h t / s r c . r o w s (double)dszie.height/src.rows (double)dszie.height/src.rows
6.int interpolation:插值方法。
机翻,如有疑问,可参考官方技术文档::InterpolationFlags

插值方法
INTER_NEAREST
Python: cv.INTER_NEAREST
最近邻插值法
INTER_LINEAR
Python: cv.INTER_LINEAR
双线性插值
INTER_CUBIC
Python: cv.INTER_CUBIC
双三次插值
INTER_AREA
Python: cv.INTER_AREA
利用像素面积关系重采样。它可能是图像抽取的首选方法,因为它能给出无摩尔纹的结果。但是当图像被放大时,它类似于inter_nearest方法。
INTER_LANCZOS4
Python: cv.INTER_LANCZOS4
8x8邻域上的Lanczos插值
INTER_LINEAR_EXACT
Python: cv.INTER_LINEAR_EXACT
位精确双线性插值
INTER_NEAREST_EXACT
Python: cv.INTER_NEAREST_EXACT
位精确最近邻插值。这将产生与PIL, scikit-image或Matlab中的最近邻方法相同的结果。
INTER_MAX
Python: cv.INTER_MAX
插值码掩码
WARP_FILL_OUTLIERS
Python: cv.WARP_FILL_OUTLIERS
标志,填充所有目标图像像素。如果其中一些与源图像中的异常值相对应,则将其设为0
WARP_INVERSE_MAP
Python: cv.WARP_INVERSE_MAP
标志,逆变换
举例, linearPolar或者logPolar 变换:
标志未设立: d s t ( ρ , ϕ ) = s r c ( x , y ) dst(ρ,ϕ)=src(x,y) dst(ρ,ϕ)=src(x,y)
标志设立: d s t ( x , y ) = s r c ( ρ , ϕ ) dst(x,y)=src(ρ,ϕ) dst(x,y)=src(ρ,ϕ)

代码示例:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	Mat img = imread("sunKnight.jpg");
	Mat dst;
	resize(img, dst, Size(512, 512));
	namedWindow("origin", WINDOW_AUTOSIZE);
	imshow("origin", img);
	namedWindow("resize", WINDOW_AUTOSIZE);
	imshow("resize", dst);
	waitKey(0);
	return 0;
}

insert image description here
注意,python版的cv2.resize,也是显示宽度,后是高度。

# PYTHON
import cv2
def main():
    img = cv2.imread("sunKnight.jpg")
    resizeImg = cv2.resize(img, (512, 256))
    cv2.namedWindow("Resize")
    cv2.imshow("Resize", resizeImg)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

insert image description here

10 图像绘制

10.1 基础类[Point/Scalar/Size/Mat]

10.1.1 Point类

Point类表示二维坐标系下的点,即由图像的x坐标和y坐标。经过测试,OpenCV统一都是横轴x,竖轴y,因此,此处x指的是width,y指的是heigth。
用法如下,只列举一个构造函数,其他初始化方法,请查询源码:

Point point;
point.x=10;
point.y =20;
//或者
Point point = Point(10 ,20)
//另外还有如下定义
typedef Point_<int> Point2i;
typedef Point_<int64> Point2l;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;
typedef Point2i Point;

10.1.2 Scalar类

Scalar类表示四个元素的数组。用来传递像素值,如RGB颜色值。对于Scalar而言,如果只有三个参数,则第四个参数不需要写出来。
用法如下,只列举一个构造函数,其他初始化方法,请查询源码:
Scalar(b, g, r, a);

template<typename _Tp> inline
Scalar_<_Tp>::Scalar_(_Tp v0, _Tp v1, _Tp v2, _Tp v3)
{
    
    
    this->val[0] = v0;
    this->val[1] = v1;
    this->val[2] = v2;
    this->val[3] = v3;
}
//另外还有如下定义
typedef Scalar_<double> Scalar;

10.1.3 Size类

Size表示矩阵数据的宽度和高度。
用法如下,只列举一个构造函数,其他初始化方法,请查询源码:
Size(_Tp width, _Tp height)

template<typename _Tp> inline
Size_<_Tp>::Size_(_Tp _width, _Tp _height)
    : width(_width), height(_height) {
    
    }
   
//另外还有如下定义
typedef Size_<int> Size2i;
typedef Size_<int64> Size2l;
typedef Size_<float> Size2f;
typedef Size_<double> Size2d;
typedef Size2i Size;

10.1.4 Mat类的初始化方法

Mat类是Opencv专门用来存储多维矩阵数据的。本节只介绍Mat类的初始化方法。值得注意的是Mat类为了减少数据的存储,它的拷贝构造函数一般只保存包含尺寸,维数,数据存储地址等信息的矩阵头,不复制数据矩阵,如果需要深度拷贝,则需要借助clone()和copyTo()函数。

补充说明:
形式:CV_<bit_depth>(S|U|F)C<number_of_channels>

  • bit_depth:比特数—代表8bite,16bites,32bites,64bites…
  • S|U|F:
    S–代表—signed int—有符号整形
    U–代表–unsigned int–无符号整形
    F–代表–float---------单精度浮点型
  • C<number_of_channels>----代表—一张图片的通道数,比如:
    channels = 1:灰度图片–grayImg—是–单通道图像
    channels = 3:RGB彩色图像---------是–3通道图像
    channels = 4:带Alph通道的RGB图像–是–4通道图像
    channels = (n):自己进行设定

初始化方法如下:

10.1.4.1 通过Mat()构造函数来初始化(rows, cols, type, scalar)

//C++
#include<opencv2/opencv.hpp>
#include<String>
#include<iostream>
using namespace std;
using namespace cv;
int main() {
    
    
	//Mat(rows, cols, type, scalar)
	Mat img(2, 2, CV_8UC3, Scalar(0 ,0 ,255));
	cout << img << endl;
	return 0;
}

insert image description here
Mat数据存储的方式是依次存储每个位置上所有通道像素数后再存储下一个。因此它的尺度为(rows × \times ×(col*channels))

10.1.4.2 通过create方法初始化[create]

//C++
#include<opencv2/opencv.hpp>
#include<String>
#include<iostream>
using namespace std;
using namespace cv;
int main() {
    
    
	Mat img;
	//Mat(rows, cols, type)
	img.create(4, 4, CV_8UC(2));
	cout << img << endl;
	return 0;
}

注意此方法不能设置矩阵初值。
insert image description here

10.1.4.3 用过[eye/ones/zeros]来初始化

//C++
#include<opencv2/opencv.hpp>
#include<String>
#include<iostream>
using namespace std;
using namespace cv;
int main() {
    
    
	//Mat(rows, cols, type)
	Mat eyeImg = Mat::eye(4,4,CV_64F);
	cout << "eyeImg = " << eyeImg << endl;
	//Mat(rows, cols, type)
	Mat onesImg = Mat::ones(4, 4, CV_32F);
	cout << "onesImg = " << onesImg << endl;
	//Mat(rows, cols, type)
	Mat zerosImg = Mat::zeros(4, 4, CV_8U);
	cout << "zerosImg = " << zerosImg << endl;
	return 0;
}

insert image description here

10.1.4.4 直接输入值进行初始化

通过Mat_类型的构造函数如下,进行初始化。

template<typename _Tp> inline
Mat_<_Tp>::Mat_(int _rows, int _cols)
    : Mat(_rows, _cols, traits::Type<_Tp>::value)
{
    
    
}
//C++
#include<opencv2/opencv.hpp>
#include<String>
#include<iostream>
using namespace std;
using namespace cv;
int main() {
    
    
	Mat Img = (Mat_<double>(3, 3) << 0, -1, 0, -1, 0, 0, 0, 0, -1);
	cout << Img << endl;
	return 0;
}

insert image description here

10.2 绘制线[line]

line()
作用:
绘制连接两点(pt1, pt2)的线段。这条线被图像边界截断。对于具有整数坐标的非反锯齿线,使用8连通或4连通的布雷森汉姆算法。粗线用圆角结尾。使用高斯滤波绘制反锯齿线。
函数形式:

C++:
void cv::line (InputOutputArray img, Point pt1, Point pt2, const Scalar & color, int thickness = 1,
int lineType = LINE_8, int shift = 0)
Python:
cv.line( img, pt1, pt2, color[, thickness[, lineType[, shift]]] ) -> img

参数解释(以C++展示的参数为例):
1.InputOutputArray img:输入图像
2.Point pt1:坐标的起始点
3.Point pt2:坐标的结束点
4.const Scalar & color:表示线段的颜色
5.int thickness:表示线段的粗细,默认为1
6. int lineType:线段的类型,默认为LINE_8
7. int shift:点坐标中小数位的个数。默认为0

线段类型 介绍
FILLED
Python: cv.FILLED
填满
LINE_4
Python: cv.LINE_4
4邻接线
LINE_8
Python: cv.LINE_8
8邻接线
LINE_AA
Python: cv.LINE_AA
抗锯齿线

代码示例:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	namedWindow("Drawing board");
	Mat img = Mat::zeros(512, 512, CV_8UC3);
	Point pt1(256, 0);
	Point pt2(256, 512);
	Scalar color(0, 0, 255);
	line(img, pt1, pt2, color, 1, 8, 0);
	
	//也可以直接传
	line(img, Point(0, 256), Point(512, 256), Scalar(0, 0, 255), 1, 8, 0);
	imshow("Drawing board", img);
	waitKey(0);
	return 0;
}

insert image description here

# PYTHON
import cv2
import numpy as np
def main():
    img = np.zeros((512,512, 3), np.uint8)
    cv2.line(img, (256, 0), (256, 512), (0, 0, 255), 1, 8, 0)
    cv2.line(img, (0, 256), (512, 256), (0, 0, 255), 1, 8, 0)
    cv2.namedWindow("Drawing board")
    cv2.imshow("Drawing board", img)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

10.3 绘制圆[circle]

circle()
作用:
绘制一个圆
函数形式:

C++:
void cv::circle(InputOutputArray img, Point center, int radius, const Scalar & color,
int thickness = 1, int lineType = LINE_8, int shift = 0)
Python:
cv.circle( img, center, radius, color[, thickness[, lineType[, shift]]] ) -> img

参数解释(以C++展示的参数为例):
1.InputOutputArray img:输入图像
2.Point center:圆的中心点
3.int radius:半径
4.const Scalar & color:绘制圆的线段颜色
5.int thickness:线段粗细,默认为1。如果是负值,表示要绘制一个已填充的圆。
6.int lineType :线段类型。默认为8
7.int shift :点坐标中小数位的个数。默认为0

代码示例:

//C++
#include<opencv2/opencv.hpp>
#include<iostream>
#include<typeinfo>
using namespace std;
using namespace cv;
int main() {
    
    
	namedWindow("Drawing board");
	Mat img = Mat::zeros(512, 512, CV_8UC3);
	Point pt1(256, 0);
	Point pt2(256, 512);
	Scalar color(0, 0, 255);
	line(img, pt1, pt2, color, 1, 8, 0);
	line(img, Point(0, 256), Point(512, 256), Scalar(0, 0, 255), 1, 8, 0);

	circle(img, Point(256, 256), 10, Scalar(100, 100, 100), -1, 8, 0);
	imshow("Drawing board", img);
	waitKey(0);
	return 0;
}

insert image description here

#PYTHON
import cv2
import numpy as np

def main():
    img = np.zeros((512,512, 3), np.uint8)
    cv2.line(img, (256, 0), (256, 512), (0, 0, 255), 1, 8, 0)
    cv2.line(img, (0, 256), (512, 256), (0, 0, 255), 1, 8, 0)
    cv2.circle(img, (256, 256), 10, (100, 100, 100), -1, 8, 0)
    cv2.namedWindow("Drawing board")
    cv2.imshow("Drawing board", img)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

10.4 绘制椭圆[ellipse]

ellipse ()
作用:
绘制简单或粗椭圆弧或填充椭圆扇区。

具有更多参数的函数cv::ellipse绘制椭圆轮廓、填充椭圆、椭圆圆弧或填充椭圆扇形。绘图代码使用一般参数形式。采用分段线性曲线逼近椭圆弧边界。如果你需要更多的椭圆渲染控制,你可以使用ellipse2Poly检索曲线,然后用polylines渲染它或用fillPoly填充它。如果您使用函数的第一个变体,并想要绘制整个椭圆,而不是圆弧,传递startAngle=0和endAngle=360。如果startAngle大于endAngle,则交换它们。下图解释了绘制蓝色圆弧的参数含义。
insert image description here

函数形式:

C++:
void cv::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)
Python:
cv.ellipse(img, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType[, shift]]] ) -> img
cv.ellipse(img, box, color[, thickness[, lineType]]

参数解释(以C++展示的参数为例):
1.InputOutputArray img:输入图像
2.Point center:圆的中心点
3.Size axes:半长轴和半短轴
4.double angle:旋转角度,单位是度
5.double startAngle:圆弧起始角度,单位是度
6.double endAngle:圆弧结束角度,单位是度
7.const Scalar & color:绘制圆的线段颜色
8.int thickness:线段粗细,默认为1。如果是负值,表示要绘制一个已填充的椭圆。
9.int lineType :线段类型。默认为8
10.int shift :点坐标中小数位的个数。默认为0
代码示例:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	namedWindow("Drawing board");
	Mat img = Mat::zeros(512, 512, CV_8UC3);
	Point pt1(256, 0);
	Point pt2(256, 512);
	Scalar color(0, 0, 255);
	line(img, pt1, pt2, color, 1, 8, 0);
	line(img, Point(0, 256), Point(512, 256), Scalar(0, 0, 255), 1, 8, 0);
	circle(img, Point(256, 256), 10, Scalar(100, 100, 100), -1, 8, 0);
	//注意size类是先宽度,后高度, X轴是起点,顺时针旋转。
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 0, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 45, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 90, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 135, 0, 360, Scalar(0, 255, 0), 1, 8, 0);

	imshow("Drawing board", img);
	waitKey(0);
	return 0;
}

insert image description here

#PYTHON
import cv2
import numpy as np

def main():
    img = np.zeros((512,512, 3), np.uint8)
    cv2.line(img, (256, 0), (256, 512), (0, 0, 255), 1, 8, 0)
    cv2.line(img, (0, 256), (512, 256), (0, 0, 255), 1, 8, 0)
    cv2.circle(img, (256, 256), 10, (100, 100, 100), -1, 8, 0)
    # axes 是先宽度,后高度,x轴为起点,顺时针旋转
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 0, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 45, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 90, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 135, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.namedWindow("Drawing board")
    cv2.imshow("Drawing board", img)
    cv2.waitKey(0)
    
if __name__ == "__main__":
    main()

10.3 绘制矩形[rectangle]

rectangle()
作用:
绘制一个矩形。
函数形式:

C++:
◆ rectangle() 【1/2】
void cv::rectangle (InputOutputArray img, Point pt1, Point pt2, const Scalar & color, int thickness = 1, int lineType = LINE_8, int shift = 0)
Python:
cv.rectangle(img, pt1, pt2, color[, thickness[, lineType[, shift]]] ) -> img
cv.rectangle(img, rec, color[, thickness[, lineType[, shift]]] ) -> img

◆ rectangle() 【2/2】
void cv::rectangle(InputOutputArray img, Rect rec, const Scalar & color, int thickness = 1, int lineType = LINE_8, int shift = 0)
Python:
cv.rectangle(img, pt1, pt2, color[, thickness[, lineType[, shift]]] ) -> img
cv.rectangle(img, rec, color[, thickness[, lineType[, shift]]] ) -> img

参数解释(以C++展示的参数为例):

1.InputOutputArray img:输入图像
2.Point pt1:Point类的pt1对象,是坐标的起始点
3.Point pt2:Point类的pt2对象,是坐标的结束点
4.const Scalar & color:表示线段的颜色
5.int thickness:表示线段的粗细,默认为1,如果是负值,表示要绘制一个已填充的矩形。
6.int lineType:线段的类型,默认为LINE_8
7.int shift:点坐标中小数位的个数。默认为0

1.InputOutputArray img:输入图像
2.Rect rec:Rect类的数据,表示图像的范围
3.const Scalar & color:表示线段的颜色
4.int thickness:表示线段的粗细,默认为1,如果是负值,表示要绘制一个已填充的矩形。
5.int lineType:线段的类型,默认为LINE_8
6.int shift:点坐标中小数位的个数。默认为0

代码示例:

//C++
#include<opencv2/opencv.hpp>
using namespace cv;
int main() {
    
    
	namedWindow("Drawing board");
	Mat img = Mat::zeros(512, 512, CV_8UC3);
	Point pt1(256, 0);
	Point pt2(256, 512);
	Scalar color(0, 0, 255);
	line(img, pt1, pt2, color, 1, 8, 0);
	line(img, Point(0, 256), Point(512, 256), Scalar(0, 0, 255), 1, 8, 0);
	circle(img, Point(256, 256), 10, Scalar(100, 100, 100), -1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 0, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 45, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 90, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 135, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	//调用方式一。
	rectangle(img, Point(256 - 10, 256 - 10), Point(256 + 10, 256 + 10), Scalar(255, 0, 0), 1, 8, 0);
	//调用方式二。
	rectangle(img, Rect(256 - 512 / 4, 256 - 512 / 4, 512 / 2, 512 / 2), Scalar(255, 0, 0), 1, 8, 0);
	imshow("Drawing board", img);
	waitKey(0);
	return 0;
}

insert image description here

#PYTHON
import cv2
import numpy as np

def main():
    img = np.zeros((512,512, 3), np.uint8)
    cv2.line(img, (256, 0), (256, 512), (0, 0, 255), 1, 8, 0)
    cv2.line(img, (0, 256), (512, 256), (0, 0, 255), 1, 8, 0)
    cv2.circle(img, (256, 256), 10, (100, 100, 100), -1, 8, 0)
    # axes 是先宽度,后高度,x轴为起点,顺时针旋转
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 0, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 45, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 90, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 135, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.rectangle(img, (256 - 10, 256 - 10), (256 + 10, 256 + 10), (255, 0, 0), 1, 8, 0)
    cv2.rectangle(img, (256 - 512 // 4, 256 - 512 // 4, 512 // 2, 512 // 2), (255, 0, 0), 1, 8, 0)
    cv2.namedWindow("Drawing board")
    cv2.imshow("Drawing board", img)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

10.4 绘制多边形[polylines]

polylines()
作用:
绘制多个多边形曲线。
函数形式:

C++:
void cv::polylines (InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar & color, int thickness = 1, int lineType = LINE_8, int shift = 0 )
Python:
cv.polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]] ) -> img

参数解释(以C++展示的参数为例):
1.InputOutputArray img:输入图像
2.InputArrayOfArrays pts:多边形曲线点集。
3.bool isClosed:标志,表示绘制的折线是否关闭。如果它们是闭合的,函数从每条曲线的最后一个顶点到它的第一个顶点绘制一条直线。
4.const Scalar & color:表示线段的颜色
5.int thickness:表示线段的粗细。
6.int lineType:线段的类型,默认为LINE_8
7.int shift:点坐标中小数位的个数。默认为0

代码示例:
注意:InputArray这个接口类可以是Mat、Mat_、Mat_<T, m, n>、vector、vector<vector>、vector。OutputArray是InputArray的派生类。

//C++
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
    
    
	namedWindow("Drawing board");
	Mat img = Mat::zeros(512, 512, CV_8UC3);
	Point pt1(256, 0);
	Point pt2(256, 512);
	Scalar color(0, 0, 255);
	line(img, pt1, pt2, color, 1, 8, 0);
	line(img, Point(0, 256), Point(512, 256), Scalar(0, 0, 255), 1, 8, 0);
	circle(img, Point(256, 256), 10, Scalar(100, 100, 100), -1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 0, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 45, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 90, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 135, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	rectangle(img, Point(256 - 10, 256 - 10), Point(256 + 10, 256 + 10), Scalar(255, 0, 0), 1, 8, 0);
	rectangle(img, Rect(256 - 512 / 4, 256 - 512 / 4, 512 / 2, 512 / 2), Scalar(255, 0, 0), 1, 8, 0);

	vector<Point> pts(4);
	pts[0] = Point(256, 0);
	pts[1] = Point(512, 256);
	pts[2] = Point(256, 512);
	pts[3] = Point(0, 256);
	polylines(img, pts, true, Scalar(0, 100, 100), 1, 8, 0);
	imshow("Drawing board", img);
	waitKey(0);
	return 0;
}

insert image description here

#PYTHON
import cv2
import numpy as np
def main():
    img = np.zeros((512,512, 3), np.uint8)
    cv2.line(img, (256, 0), (256, 512), (0, 0, 255), 1, 8, 0)
    cv2.line(img, (0, 256), (512, 256), (0, 0, 255), 1, 8, 0)
    cv2.circle(img, (256, 256), 10, (100, 100, 100), -1, 8, 0)
    # axes 是先宽度,后高度,x轴为起点,顺时针旋转
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 0, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 45, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 90, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 135, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.rectangle(img, (256 - 10, 256 - 10), (256 + 10, 256 + 10), (255, 0, 0), 1, 8, 0)
    cv2.rectangle(img, (256 - 512 // 4, 256 - 512 // 4, 512 // 2, 512 // 2), (255, 0, 0), 1, 8, 0)
   
    pts = np.array([[256, 0], [512, 256], [256, 512], [0, 256]], np.int32)
    pts = pts.reshape((-1, 1, 2))
    cv2.polylines(img, [pts], True, (0, 100, 100), 1, 8, 0)
    cv2.namedWindow("Drawing board")
    cv2.imshow("Drawing board", img)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

10.5 在图像中绘制文字字符串[putText]

putText()
作用:
绘制文本字符串。函数cv::putText在图像中呈现指定的文本字符串。不能使用指定字体呈现的符号将替换为问号。

函数形式:

C++:
void cv::putText(InputOutputArray img, const String & text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1, int lineType = LINE_8, bool bottomLeftOrigin = false )
Python:
cv.putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]]) -> img

参数解释(以C++展示的参数为例):
1.InputOutputArray img: 输入图像
2.const String & text:需要展示的字符串
3.Point org:图像中文本字符串的左下角坐标。
4.int fontFace:字体类型
5.double fontScale:字体大小,表示与字体的基本大小相乘的字体比例因子。
6.Scalar color:表示线段的颜色
7.int thickness:表示线段的粗细。
8.int lineType:线段的类型,默认为LINE_8
9.bool bottomLeftOrigin = false 当为true时,图像数据来源位于左下角。否则,它在左上角。

字体类型 解释
FONT_HERSHEY_SIMPLEX 正常大小无衬线(黑体)字体
FONT_HERSHEY_PLAIN 小尺寸无衬线(黑体)字体
FONT_HERSHEY_DUPLEX 正常大小的无衬线字体(比FONT_HERSHEY_SIMPLEX更复杂)
FONT_HERSHEY_COMPLEX 正常大小的衬线字体
FONT_HERSHEY_TRIPLEX 正常大小的衬线字体(比FONT_HERSHEY_COMPLEX更复杂)
FONT_HERSHEY_COMPLEX_SMALL FONT_HERSHEY_COMPLEX的小版本
FONT_HERSHEY_SCRIPT_SIMPLEX 书写风格的字体
FONT_HERSHEY_SCRIPT_COMPLEX 更复杂的变体FONT_HERSHEY_SCRIPT_SIMPLEX
FONT_ITALIC 斜体标志

代码示例:

//C++
#include<opencv2/opencv.hpp>
#include<String>
using namespace std;
using namespace cv;
int main() {
    
    
	namedWindow("Drawing board");
	Mat img = Mat::zeros(512, 512, CV_8UC3);
	Point pt1(256, 0);
	Point pt2(256, 512);
	Scalar color(0, 0, 255);
	line(img, pt1, pt2, color, 1, 8, 0);
	line(img, Point(0, 256), Point(512, 256), Scalar(0, 0, 255), 1, 8, 0);
	circle(img, Point(256, 256), 10, Scalar(100, 100, 100), -1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 0, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 45, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 90, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	ellipse(img, Point(256, 256), Size(512 / 4, 512 / 16), 135, 0, 360, Scalar(0, 255, 0), 1, 8, 0);
	rectangle(img, Point(256 - 10, 256 - 10), Point(256 + 10, 256 + 10), Scalar(255, 0, 0), 1, 8, 0);
	rectangle(img, Rect(256 - 512 / 4, 256 - 512 / 4, 512 / 2, 512 / 2), Scalar(255, 0, 0), 1, 8, 0);
	vector<Point> pts(4);
	pts[0] = Point(256, 0);
	pts[1] = Point(512, 256);
	pts[2] = Point(256, 512);
	pts[3] = Point(0, 256);
	polylines(img, pts, true, Scalar(0, 100, 100), 1, 8, 0);
	
	String text = "Atomic structure diagram";
	putText(img, text, Point(256 - 512 / 4, 256 - 512 / 4), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 255, 255), 1, 8, false);
	imshow("Drawing board", img);
	waitKey(0);
	return 0;
}

insert image description here

#PYTHON
import cv2
import numpy as np

def main():
    img = np.zeros((512,512, 3), np.uint8)
    cv2.line(img, (256, 0), (256, 512), (0, 0, 255), 1, 8, 0)
    cv2.line(img, (0, 256), (512, 256), (0, 0, 255), 1, 8, 0)
    cv2.circle(img, (256, 256), 10, (100, 100, 100), -1, 8, 0)
    # axes 是先宽度,后高度,x轴为起点,顺时针旋转
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 0, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 45, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 90, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.ellipse(img, (256, 256), (512 // 4, 512 // 16), 135, 0, 360, (0, 255, 0), 1, 8, 0)
    cv2.rectangle(img, (256 - 10, 256 - 10), (256 + 10, 256 + 10), (255, 0, 0), 1, 8, 0)
    cv2.rectangle(img, (256 - 512 // 4, 256 - 512 // 4, 512 // 2, 512 // 2), (255, 0, 0), 1, 8, 0)
    pts = np.array([[256, 0], [512, 256], [256, 512], [0, 256]], np.int32)
    pts = pts.reshape((-1, 1, 2))
    cv2.polylines(img, [pts], True, (0, 100, 100), 1, 8, 0)

    cv2.putText(img, "Atomic structure diagram",(256 - 512 // 4, 256 - 512 // 4), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
                (255, 255, 255), 1, 8, False)

    cv2.namedWindow("Drawing board")
    cv2.imshow("Drawing board", img)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

总结

This article only summarizes the functions that I think are commonly used. In the official Opencv documentation, there are many functions that have not been introduced. If this article is not written, you can query the official OpenCV documentation . Thank you readers for reading. If you think it is helpful to you, you can give the little brother a thumbs up.

Finally, remember Mr. Mao Xingyun and thank Mr. Mao Xingyun for his guidance. This article mainly refers to Mr. Mao Xingyun's "Introduction to OpenCV3 Programming".

Guess you like

Origin blog.csdn.net/weixin_43610114/article/details/126016394