OpenCV Basics

This blog post covers the basics of OpenCV, a popular computer vision library. It explains how to load, display, and save images using OpenCV functions. Additionally, it delves into the Mat class, which is used to represent images in OpenCV as matrices. The post demonstrates how to create Mat objects, access their properties, and traverse and manipulate pixel values using both array-based and pointer-based methods. ## Hello World

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
cout << "start\n";
// Read an image
Mat src = imread("E:\\Datum\\Code\\CV4\\CV4\\a.png");
if (src.empty()) {
printf("could not open");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE); // Create a window with the given title and automatic image size
// In OpenCV 3, use namedWindow("input", CV_WINDOW_AUTOSIZE)
imshow("input", src); // Display the image in the "input" window
waitKey(0); // Prevent the window from closing immediately, wait for user input
destroyAllWindows(); // Destroy all windows
return 0;
}
  1. In OpenCV 4, you can directly use #include <opencv2/opencv.hpp> to import all OpenCV functions.
  2. using namespace cv; uses the OpenCV namespace.
  3. Define a Mat variable src and read an image into it.
  4. Perform robustness check; if the loaded image is not empty, display it.
  5. Use namedWindow("input", WINDOW_AUTOSIZE); to create a window. The first parameter is the window name, and the second parameter is the window size, which in OpenCV 4 is defined as automatic window size. In OpenCV 3, use nameWindow("input", CV_WINDOW_AUTOSIZE) to define the window.
  6. Use imshow("input", src) to display the image. The first parameter is the window to display in, and the second parameter is the image to display.
  7. To prevent the displayed image from disappearing immediately, use waitKey(0) to wait for user input.
  8. Use destroyAllWindows() to destroy all windows.

Image File Loading, Displaying, and Saving

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int main() {
// Mat src = imread("./lenna.tiff", IMREAD_COLOR); // Load as a color image, default mode, transparency channel will be discarded
// Mat src = imread("./lenna.tiff", IMREAD_GRAYSCALE); // Load as a grayscale image
// Mat src = imread("./lenna.tiff", IMREAD_ANYCOLOR); // Load with any color format
Mat src = imread("./test.png", IMREAD_UNCHANGED); // Do not change the number of channels, supports loading PNG transparency channel
if (src.empty()) {
std::cout << "can not open" << std::endl;
}
// namedWindow("input", WINDOW_AUTOSIZE); // Automatically fit image size, cannot be changed
// namedWindow("input", WINDOW_FREERATIO); // Freely change image display size
namedWindow("input", WINDOW_NORMAL); // Can change image display size
imshow("input", src);
waitKey(0);
destroyAllWindows();
imwrite("./test.png", src); // Save as the corresponding format based on the file extension

return 0;
}

Image File Loading

The imread("filename", load_mode) function: 1. By default, loads a BGR color image. 2. Supports grayscale and any color format images.

Common load modes include: 1. IMREAD_COLOR: Load as a color image, the default mode, transparency channel will be discarded. 2. IMREAD_GRAYSCALE: Load as a grayscale image. 3. IMREAD_ANYCOLOR: Load with any color format. 4. IMREAD_UNCHANGED: Do not change the number of channels, supports loading PNG transparency channel.

Window and Display

The imshow("window_name", display_mode) function:

Display modes include: 1. WINDOW_AUTOSIZE: Automatically fit the image size, cannot be changed. 2. WINDOW_FREERATIO: Freely change the image display size. 3. WINDOW_NORMAL: Can change the image display size.

Image File Saving

The imwrite("save_address", variable) function: Saves the image in the corresponding format based on the file extension.

Mat Class

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
// Image object Mat
// An image is a matrix, Mat is an object that stores matrices
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main() {
Mat src = imread("./lenna.tiff");
if (src.empty()) {
cout << "cannot open" << endl;
}
namedWindow("input", WINDOW_FREERATIO);
imshow("input", src);
int width = src.cols; // Get the image width
int height = src.rows; // Get the image height
int dim = src.channels(); // Get the number of image channels
int d = src.depth(); // Image depth, enum type
int t = src.type(); // Image type, enum type
if (t == CV_8UC3) {
cout << "ok" << endl;
}
cout << width << endl << height << endl << dim << endl << d << endl << t << endl;
waitKey(0);
destroyAllWindows();
return 0;
}

An image is essentially a matrix, so in OpenCV, images are stored in matrix form, i.e., Mat. Common attributes of Mat include:

  1. src.cols; // Get the image width.
  2. src.rows; // Get the image height.
  3. src.channels(); // Get the number of image channels.
  4. src.depth(); // Image depth, enum type, returns the depth of each pixel element. Common values include CV_8U (8-bit unsigned integer), CV_16U (16-bit unsigned integer), CV_32F (32-bit float), etc.
  5. src.type(); // Image type, enum type. Common types include CV_8U (8-bit unsigned integer), CV_8S (8-bit signed integer), CV_16U (16-bit unsigned integer), CV_16S (16-bit signed integer), CV_32F (32-bit float), CV_64F (64-bit float), etc.
  6. src.size // Returns a tuple containing the number of rows and columns of the image.
  7. src.empty(): Check if the Mat object is empty.
  8. src.total(): Returns the total number of elements in the Mat object.

Creating and Using Mat Objects

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
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
Mat src = imread("./lenna.tiff");
Mat t1 = Mat(256, 256, CV_8UC3); // Create a 256x256 grayscale image
t1 = Scalar(0, 0, 256); // Assign values to the image matrix
imshow("t1", t1);
Mat t2 = Mat(Size(512, 512), CV_8UC3); // Create a 512x512 grayscale image
t2 = Scalar(0, 0, 256); // Assign values to the image matrix
imshow("t2", t2);
Mat t3 = Mat::zeros(Size(256, 256), CV_8SC3); // Directly create a 256x256 all-black image during creation
imshow("t3", t3);
// Create from an existing image
Mat t4 = src;
// t4 = Scalar(0, 255, 255); // Assigning values to t4 will also change t5
imshow("t4", t4);
// Create using the clone method
Mat t5 = src.clone();
t5 = Scalar(0, 255, 255); // Assigning values to t5 will not change t4
imshow("t5", t5);
Mat t6;
src.copyTo(t6);
imshow("t6", t6);
Mat t7 = Mat::zeros(src.size(), src.type()); // Create an all-zero image with the same size as src
waitKey(0);
destroyAllWindows();
return 0;
}

Creating Mat Objects

  1. Use Mat t1 = Mat(256, 256, CV_8UC3); to create a 256x256 grayscale image. The type represents an unsigned 3-channel image.
  2. t1 = Scalar(0, 0, 256); assigns constant values to the image matrix.
  3. Mat t2 = Mat(Size(512, 512), CV_8UC3); creates a 512x512 grayscale image.
  4. Mat t3 = Mat::zeros(Size(256, 256), CV_8SC3); directly creates a 256x256 all-black image with an unsigned 3-channel type during creation.
  5. Mat t4 = src; creates t4 directly from src.
  6. Mat t5 = src.clone(); creates a clone of src.
  7. Mat t6; src.copyTo(t6); copies src to t6.
  8. Mat t7 = Mat::zeros(src.size(), src.type()); creates an all-zero image with the same size and type as src.

Traversing and Accessing Pixel Values

OpenCV provides several methods to access and manipulate individual pixels in an image. Here's a concise overview of the different techniques:

1. Array-based Pixel Access with at

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <opencv2/opencv.hpp>
using namespace cv;

void methodAt(Mat& image) {
for(int y = 0; y < image.rows; y++) {
for(int x = 0; x < image.cols; x++) {
// For grayscale images
// uchar& pixel = image.at<uchar>(y, x);
// pixel = ...;

// For color (BGR) images
Vec3b& color = image.at<Vec3b>(y, x);
// Operate on pixel, e.g., invert color
color[0] = 255 - color[0]; // B
color[1] = 255 - color[1]; // G
color[2] = 255 - color[2]; // R
}
}
}
  • Use nested loops to iterate over every row and column of the image
  • Access color pixels with image.at<Vec3b>(y, x)
  • Access grayscale pixels with image.at<uchar>(y, x)
  • Directly read and write pixel values, e.g., pixel[0] = 255 - blue
  • Requires obtaining the image's height, width, and number of channels

2. Pointer-based Pixel Access

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void methodPointer(Mat& image) {
for(int y = 0; y < image.rows; y++) {
// Get a pointer to the start of the y-th row
uchar* row = image.ptr<uchar>(y);
for(int x = 0; x < image.cols; x++) {
// For grayscale images
// uchar& pixel = row[x];
// pixel = ...;

// For color (BGR) images
// BGR format, each pixel occupies 3 uchars
uchar& blue = row[x * 3];
uchar& green = row[x * 3 + 1];
uchar& red = row[x * 3 + 2];
// Operate on pixel
blue = 255 - blue;
green = 255 - green;
red = 255 - red;
}
}
}
  • Use nested loops to iterate over every row and column of the image
  • Get a pointer to the start of each row with image.ptr<uchar>(y)
  • Access color pixels by incrementing the pointer by x * 3 for each channel
  • Access grayscale pixels by incrementing the pointer by x

3. Iterator-based Pixel Access

1
2
3
4
5
6
7
8
9
void methodIterator(Mat& image) {
// cv::Mat_<Vec3b> is the iterator type for color images
for(auto it = image.begin<Vec3b>(); it != image.end<Vec3b>(); it++) {
// Invert color
(*it)[0] = 255 - (*it)[0]; // B
(*it)[1] = 255 - (*it)[1]; // G
(*it)[2] = 255 - (*it)[2]; // R
}
}
  • Use iterators to traverse the image pixels
  • image.begin<Vec3b>() returns an iterator to the first pixel in the image
  • image.end<Vec3b>() returns an iterator to the position after the last pixel
  • Directly access and modify pixel values using the iterator dereferencing operator *it

These techniques provide different ways to access and manipulate pixel data in OpenCV images. The choice depends on personal preference, code readability, and performance considerations for the specific use case.


OpenCV Basics
http://jingmengzhiyue.top/2024/03/14/OpenCV-Basics/
作者
Jingmengzhiyue
发布于
2024年3月14日
许可协议