Introduction
In the previous tutorial we saw the Hello World application of OpenCV. This post is about one base functionality of OpenCV – reading and writing image data. We are going to use this functionality in every upcoming tutorial and that is why I decided to make a separate post about it. I have prepared seven different examples showing ways to read and write image data. We are going to read data from images and write again to new images.
The example as with the previous tutorial are available in GitHub. You can check them there.
Reading color image and writing it in the same format
Firstly, we are going to read data from color images, which is in JPEG format and save it to another JPEG file. Here is the code. I have written it into a separate function, which my program calls in the main method.
void readColorJPGWriteSameType() { std::string l_pathToInputImage{ "../Resources/city.jpg" }; std::string l_pathToOutputImage{ "../Resources/city_copy.jpg" }; Mat l_image; l_image = imread(l_pathToInputImage, IMREAD_UNCHANGED); if (!l_image.data) { std::cout << "No image data \n"; return; } namedWindow("Display Image", WINDOW_NORMAL); imshow("Display Image", l_image); imwrite(l_pathToOutputImage, l_image); }
Firstly I am storing the image paths of the input and output images into two string objects. I will use them later. If your images are somewhere else, make sure to provide the correct paths.
Next, I am creating one Mat object. The Mat class purpose is to contain the image data we read from the images. Most of the OpenCV functions require or return objects of this type. As you can see from the next function call, we store the returned data inside the Mat object.
Reading the image
The imread function reads image data from a given file. We provide the file name as an argument to that function. The second argument is a flag, which gives more information to the OpenCV function. IMREAD_UNCHANGED means that OpenCV will read the image data as it is. OpenCV will not do any change to it. In the other examples you will see the usage of the other flags. More information about them here.
After we called the function, it is supposed to store the image data that was read inside the l_image object. Next thing we do is a check whether we have read the images correctly. If for some reason the OpenCV function was not able to read the images it will return a null pointer. In that case we will print a message and return.
Displaying the image on the display
After we have read images, we will display them on the computer display. This is possible with the next two statements. The namedWindow function will create one window where we will display the images. The first argument is the name, which we want to be displayed on the window. The second argument is a flag, which shows how we want to display the window. The WINDOW_NORMAL mode will display the window normally. There are more modes. You can find information about them here. Just note that calling this function is not mandatory to display a window. However, if you don’t use it you will not be able to control how OpenCV will display the window. So this function gives you control on the displaying of the window and its properties.
The imshow function will display images on the window we created and set previously. If we haven’t called the previous function in will create the window by itself. First argument of this function is the name, that it should display on the window. The second argument is the object which holds the image data. The function will display that image data. If we were to do some manipulations to the images, those manipulations would be visible as well.
Writing the image into a file
Lastly, after we have read and displayed the images it is time to save them into files. For this purpose we have the imwrite function. This function takes two argument. First argument is the path of the new image we want to save the data to. The second argument is the image data we want to write. In case we have provided a path to an existing image, OpenCV will overwrite the given image file.
Now we are done. Following is my result. You can see that the window is named “Display Image” as we provided in the functions.

Reading a color image and writing it in a different format
Next example is very similar to the previous one. The only difference is that we are saving the images in a different format. Previously we read an JPEG image and saved it as a JPEG image. Now we will read a JPEG image and save it as a PNG. The good thing about OpenCV images codecs libraries is that they are able to automatically find out the images format and add the needed headers. All that is left for the user is to provide the extension. You will see in the next example.
void readColorJPGWriteDifferentType() { std::string l_pathToInputImage{ "../Resources/city.jpg" }; std::string l_pathToOutputImage{ "../Resources/city_copy.png" }; Mat l_image; l_image = imread(l_pathToInputImage, IMREAD_UNCHANGED); if (!l_image.data) { std::cout << "No image data \n"; return; } namedWindow("Display Image", WINDOW_NORMAL); imshow("Display Image", l_image); imwrite(l_pathToOutputImage, l_image); }
As you can see from the example above everything is the same as the previous example only the l_pathToOutputImage variable gets different value. The image is with .png extension. OpenCV automatically recognizes it and knows that it should save the image in PNG format. I will not go into details since the example is the same as the previous one.
Just for the sake of the example I am providing another function that reads PNG images and saves them in JPEG format. When you run the example and if you provide it with images that uses the Alpha channel (has some transparency regions) you will see that the transparency will disappear when saved as a JPEG.
void readColorPNGWriteDifferentType() { std::string l_pathToInputImage{ "../Resources/love.png" }; std::string l_pathToOutputImage{ "../Resources/love_copy.jpg" }; Mat l_image; l_image = imread(l_pathToInputImage, IMREAD_COLOR); if (!l_image.data) { std::cout << "No image data \n"; return; } namedWindow("Display Image", WINDOW_NORMAL); imshow("Display Image", l_image); imwrite(l_pathToOutputImage, l_image); }
Also you can see that I am using IMREAD_COLOR flag when reading the image. It will read the image in BGR color format but in the end we are getting one and the same result.
Reading an image in a grayscale mode
Next example shows how to read color images directly as a grayscale. In grayscale mode only gray color with its intensities is displayed. The colors are transformed into intensities. OpenCV does this automatically. The only thing that is different from the previous examples is that we use IMREAD_GRAYSCALE with the imread function. Everything else is the same. This flag will cause OpenCV to read and transform the colors into intensities.
void readGrayscaleJPGWriteSameType() { std::string l_pathToInputImage{ "../Resources/city.jpg" }; std::string l_pathToOutputImage{ "../Resources/city_gray_copy.jpg" }; Mat l_image; l_image = imread(l_pathToInputImage, IMREAD_GRAYSCALE); if (!l_image.data) { std::cout << "No image data \n"; return; } namedWindow("Display Image", WINDOW_NORMAL); imshow("Display Image", l_image); imwrite(l_pathToOutputImage, l_image); }
The end result will look like this:

Reading an image in reduced format
There is one more mode which we can use with imread – reduced mode. It can be used with both color and grayscale modes. In order to use it we need to set the flag in imread to IMREAD_REDUCED_COLOR_X or IMREAD_REDUCED_GRAYSCALE_X where X could be one of the following – 2, 4 or 8. These numbers control how many times the image will be scaled down. For example if we have an image with size 512 x 512 and we use 2, the result image will be with size 256 x 256. Here is example on how to use it. Note that everything is the same as the previous examples only the flag in the imread function is different:
void readGrayscaleReducedJPGWriteSameType() { std::string l_pathToInputImage{ "../Resources/city.jpg" }; std::string l_pathToOutputImage{ "../Resources/city_gray_reduced_copy.jpg" }; Mat l_image; l_image = imread(l_pathToInputImage, IMREAD_REDUCED_GRAYSCALE_4); if (!l_image.data) { std::cout << "No image data \n"; return; } namedWindow("Display Image", WINDOW_NORMAL); imshow("Display Image", l_image); imwrite(l_pathToOutputImage, l_image); }
Conclusion
In this post we saw how to read an image in OpenCV in different format. Also, we saw how to display the image in a window. Lastly we saw how to save the image. We found out how OpenCV makes our lifes easier by automatically getting the correct image format while reading and automatically writing it in the desired format. Also, we saw that OpenCV automatically can transform color images into grayscale ones.
You can find and download the examples from the below link and compare against your implementation.
Next, we will see how to scan the image matrix and manipulate its data.

Passionate developer, loving husband and caring father. As an introvert programming is my life. I work as a senior software engineer in a big international company. My hobbies include playing computer games (mostly World of Warcraft), watching TV series and hiking.