datahacker.rs@gmail.com

OpenCV #001 Manipulating Image Pixels

OpenCV #001 Manipulating Image Pixels

Digital Image Processing using OpenCV (Python & C++)

Highlight: In this blog post, we will give an overview of what a pixel is, how a computer understands it and how pixels can be accessed and manipulated using OpenCV.

1. What’s a Pixel?

When we talk about video files, we are mainly concerned with quality and resolution. That is why most of us have a full HD, 4k Ultra HD, 8k Ultra HD. However, if we zoom in a photo, we will see small tiny square boxes close to each other. All these tiny boxes collectively represent an image, and they are known as pixels. So now, what is a pixel?

In a few words, a pixel is a small element of a picture. Each pixel represents a color which is a combination of three color channels: red, green and blue. With a million combination of these colours, we can represent any colour and any image. Wow!

In computers, images are commonly stored as matrices. Every pixel has 3 intensity values for red, green and blue (RGB). To represent a single channel intensity, we will use values from 0-255, and we use 8 bits for a color channel per pixel. For grayscale images, on the other hand, we use values from 0-255 to represent gray intensities: 0-black and 255-white.

2. Coordinate System in an Image

An image can be seen as a grid of pixels. A coordinate system can be used to access each pixel. For example, let’s pick 2 coordinate points $$(x,y)$$ on the grid, $$(0,0)$$. This corresponds to the upper left corner of the image and as the values for x and y increase we move down and to the right.

Note: pixels are accessed with $$(x, y)$$ coordinates. The $$x$$ value represents the columns and the $$y$$ value represents the rows.

After that has been clarified, it’s also good to know that OpenCV reads these channel order $$(R, G, B)$$, in reverse $$(B, G, R)$$. Now, let’s see how we can access and manipulate pixels on an image.

4. Pixel access and manipulation in C++

.wp-block-code {
border: 0;
}

.wp-block-code > div {
overflow: auto;
}

.shcb-language {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
-webkit-clip-path: inset(50%);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
position: absolute;
width: 1px;
word-wrap: normal;
word-break: normal;
}

.hljs {
box-sizing: border-box;
}

.hljs.shcb-code-table {
display: table;
width: 100%;
}

.hljs.shcb-code-table > .shcb-loc {
color: inherit;
display: table-row;
width: 100%;
}

.hljs.shcb-code-table .shcb-loc > span {
display: table-cell;
}

.wp-block-code code.hljs:not(.shcb-wrap-lines) {
white-space: pre;
}

.wp-block-code code.hljs.shcb-wrap-lines {
white-space: pre-wrap;
}

.hljs.shcb-line-numbers {
border-spacing: 0;
counter-reset: line;
}

.hljs.shcb-line-numbers > .shcb-loc {
counter-increment: line;
}

.hljs.shcb-line-numbers .shcb-loc > span {
}

.hljs.shcb-line-numbers .shcb-loc::before {
border-right: 1px solid #ddd;
content: counter(line);
display: table-cell;
text-align: right;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
width: 1%;
}
#include <opencv2/opencv.hpp> //Include file for every supported OpenCV function. Hint: Slow to compile.

using namespace cv;  // optional
using namespace std;

int main ( int argc, char** argv  ) {

// initialization
cv::Mat image;
int x=0, y=0;

// place an image in the working folder

// we will use this command to show an image.
// the first argument is the title of the window, the second one is the loaded image (MAT format)
cv::imshow("Window 1", image);

// we wait for a key to be pressed, and then we exit.
cv::waitKey(0);

// the following piece of code reads a single pixel value
// then it prints it.

// 3 channel image with BGR color (type 8UC3)
// the values can be stored in "int" or in "uchar". Here int is
//used.
cv::Vec3b intensity = image.at<Vec3b>(y, x);

float blue = intensity.val[0];
float green = intensity.val[1];
float red = intensity.val[2];

std::cout << "Blue:" << blue << std::endl;
std::cout << "Green:" << green  << std::endl;
std::cout << "Red:" << red << std::endl;

// changing a single pixel color at the location (x,y)
// get a pixel
cv::Vec3b color = image.at<Vec3b>(Point(x,y));

color[0]=0;
color[1]=255;
color[2]=0;

// set a pixel back to the image
image.at<Vec3b>(Point(x,y)) = color;

cv::imshow("Changed one pixel value", image);
waitKey(0);

// change the part of the image into a certain color
// this code snippet will loop over an upper-top rectangle,
// it will access each pixel and change its value.
// Following OpenCV's format BGR, we will get green pixels.
// That is, a green rectangle in the upper top image.

for (x=0; x<100; x++) {

for (y=0; y<100; y++ ){

// get a pixel
cv::Vec3b color = image.at<Vec3b>(Point(x,y));

color[0]=0;
color[1]=255;
color[2] =0;

// set a pixel back to the image
image.at<Vec3b>(Point(x,y)) = color;

}
}

cv::imshow("Changed a part of the image", image);
waitKey(0);

// Saving the image
cv::imwrite( "new_image.jpg", image);

return 0;
}Code language: PHP (php)

Explanation

We imported the necessary libraries, loaded the image from the disk and displayed it.

Next, at the top left corner of the frame, coordinate $$(0, 0)$$, we replaced the original pixel value into a green pixel. However, this cannot be easily seen, except when we zoom closely at the image. Therefore, we selected a $$100×100$$-pixel region from $$(0,0)$$ to $$(99,99)$$ and repainted the color with this range to all green.

After that, the bottom image shows that we have successfully drawn a green square in our image. That is, we have replaced all pixels intensity values that fit that rectangle with green pixels.

Summary

To sum up, we have learned what a pixel is, how to access and manipulate the pixels in an image using NumPy’s built-in array slicing functionality. In addition, we gave an overview of how this can be done in C++ as well.

In the next post, we will see how to read, write and display videos using OpenCV.