1

Using opencv and c++ I am attempting to write a program that given a file path, the program will duplicate every image in that file. This is what I have written using imread and imwrite:

#include <filesystem>
#include <fstream>
using namespace std;
using namespace cv;
namespace fs = std::filesystem;

Mat duplicateImage(string filename) {
    // Load the input image
    Mat image = imread(filename, IMREAD_UNCHANGED);

    // Create a duplicate image
    Mat duplicate = image.clone();

    return duplicate;
}

int main(int argc, char** argv)
{
 
    string directory_name = "C:\\My\\File\\Path\\Name";
    vector<string> files_list;

    ifstream file_stream(directory_name);
    string line;
    while (getline(file_stream, line)) {
        files_list.push_back(line);
    }

    // Duplicate each image in the directory
    for (string filename : files_list) {
        Mat duplicate = duplicateImage(filename);
        string output_filename = filename + "_copy"; // new filename for the duplicate;
            cv::imwrite(output_filename, duplicate);
    }
}

When I open up the file path there are no changes made to the file.

I had initially attempted to fo this with fstream which resulted in the same issue, the file not being modified at all. any advice would be greatly appriciated!

EDIT: I have discovered a bug - I am not even entering the for loop, I know this because I did a print statement and am not seeing it in the concile. I'm am unsure why I would not be entering the for loop.

wohlstad
  • 12,661
  • 10
  • 26
  • 39
cvstudent
  • 15
  • 6
  • 2
    How will it know whether you want a JPEG or a PNG written if the output filename is `inputImage.jpg_copy` ? – Mark Setchell Apr 05 '23 at 06:42
  • This is not a good way to copy images. You will lose all your metadata (copyright, EXIF, GPS data, camera make/model, ICC colour profiles, IPTC data). You will also potentially change compression factor (making images needlessly larger or smaller and losing quality) and inflate palette images into full RGB images costing disk space. – Mark Setchell Apr 05 '23 at 09:11
  • @MarkSetchell The reason im wanting to copy the images is because I need to alter the original image to be a certain size and the copy image to be a different size. do you have any ideas for a different route i could take? – cvstudent Apr 05 '23 at 16:46
  • It's hard to answer you. I don't know 1) what format your images are 2) how big you want the output images 3) whether you need to retain metadata 4) whether you just want the job done, or are insistant on using OpenCV and C++. – Mark Setchell Apr 05 '23 at 16:53
  • @MarkSetchell my images are .jpg currents and My end goal will be to make the duplicate images be 200 * 200, I do not need to retiain the metadata, and I have to use c++ – cvstudent Apr 05 '23 at 17:14
  • How about some *"debug printing"*? Print the name and size of each file you open and the name of the output file? Try using your debugger. – Mark Setchell Apr 05 '23 at 17:32

1 Answers1

0

There are 2 issues in your code:

1. Getting the list of files:

You cannot use ifstream with getline to get a list of files in a directory (which is why files_list is empty).
You can use std::filesystem::directory_iterator for that.
In your case it should be something like:

for (const auto& entry : std::filesystem::directory_iterator(directory_name))
{
    files_list.push_back(entry.path().string());
}

2. Saving the images with cv::imwrite:

As you can see in the cv::imwrite documentation:

The image format is chosen based on the filename extension (see cv::imread for the list of extensions).

(emphasis is mine)

The list of extensions is detailed here: cv::imread. Among them: .jpg (for JPEG files), .png (for Portable Network Graphics), etc.

Since you add a "_copy" suffix to your filenames there are no longer with one of the supported extensions and the image is not saved.

You can use e.g. "_copy.jpg" or "_copy.png" as a suffix.
You can also determine the extension of the current filename dynamically (see here:How to get file extension from string in C++) and add it to the generated filename.

However:

If you only need to copy the image files as is (without modifying the image content), you can simply use std::filesystem::copy without reading the image content etc.

wohlstad
  • 12,661
  • 10
  • 26
  • 39
  • Hello! thank you for your answer - I changed this line to look like ''' for (string filename : files_list) { Mat duplicate = duplicateImage(filename); string output_filename = filename + "_copy.jpg"; // new filename for the duplicate; cv::imwrite(output_filename, duplicate); } ''' because the images in the file are of the .jpg extension and I am still not seeing any changes in the file. Do you know a reason why that might be? – cvstudent Apr 05 '23 at 16:51
  • I think you are not getting the list of files in the directory properly. Updated my answer. – wohlstad Apr 06 '23 at 04:16