Почему моя программа ищет "desktop.bmp"?

Я работаю над программой, в которой перебираю папку, содержащую примерно 500 изображений в формате .bmp. Изображениям присваиваются имена с использованием случайных букв и цифр (пример «151t12_4.bmp»). Я использую OpenCV с использованием С++ в Visual Studio 2022 для внесения изменений в изображения (открытие, закрытие, контуры, расширение и т. д.). Я сохраняю результаты характеристик изображения (длина, ширина, черные пиксели и т. д.) в файле CSV. Все работает нормально, за исключением того, что программа пытается прочитать "desktop.bmp" в папке, хотя ее не существует.

Он всегда останавливает запуск программы, потому что не может найти файл (очевидно), поэтому я переименовал файл в desktop.bmp, и он работал нормально. В чем причина такого необычного поведения и как это исправить? Я попытался использовать другую папку с изображениями, но она вернула ту же ошибку.

Еще одна проблема, которую я заметил, заключается в том, что программа сохраняет 2 записи для «desktop.bmp» в файле CSV, который я создаю. Теперь это не проблема сама по себе, но я хотел бы знать, что вызывает это и как это исправить?

Вот как выглядит мой код:

#include <opencv2/core/core.hpp>
#include <opencv2/core/types.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <iostream>
#include <math.h>
#include <string>
#include <algorithm>
#include <fstream>
#include <filesystem> 

using namespace cv;
using namespace std;
using directory_iterator = filesystem::directory_iterator;
namespace fs = filesystem;
string get_stem(const fs::path& p) { return p.stem().string(); }

int main()
{
    fstream image_details;
    fstream file1("image_details.csv");
    if (!file1.is_open()) {
        image_details.open("image_details.csv", ios::out);
        image_details << "Image Name, Width, Height \n";
    }

    else
        image_details.open("image_details.csv", ios::app);


    string img_path = "C:\\Users\\TheHiredGoon\\Desktop\\image_folder"

    for (const auto& dirEntry : directory_iterator(img_path))
    {
        string img_name, path = get_stem(dirEntry);
        img_name = path;
        path = img_path + "\\" + img_name + ".bmp";

        Mat src = imread(path);
        Mat src_grey = imread(path, IMREAD_GRAYSCALE);

        Mat thresh;
        threshold(src_grey, thresh, 0, 255, THRESH_OTSU | THRESH_BINARY);
        vector<vector<Point>> contours;
        vector<Vec4i> hierarchy;
        findContours(thresh, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);

        //sorting the contours by size (descending order)
        sort(contours.begin(), contours.end(), [](const vector<Point>& c1, const vector<Point>& c2)
            {
                return contourArea(c1, false) > contourArea(c2, false);
            });

        for (int x = 0; x < contours.size(); x++) {
            cout << "Size of contour " << x << " = " << contours[x].size() << endl;
        }

        vector<vector<Point> > contours_poly(contours.size());
        vector<Rect> boundRect(contours.size());
        int area[20] = {}, perimeter[20] = {};
        for (size_t i = 0; i < contours.size(); i++)
        {
            approxPolyDP(contours[i], contours_poly[i], 3, true);
            boundRect[i] = boundingRect(contours_poly[i]);
            area[i] = contourArea(contours_poly[i]);
            perimeter[i] = arcLength(contours_poly[i], true);
        }

        Mat drawing = src_grey.clone();
        for (size_t i = 0; i < contours.size(); i++)
        {
            rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 2);
        }

        Mat img_crop;
        img_crop = drawing(boundRect[1]);
        // the compiler indicates that the above line is the "Next statement to execute when this thread returns from the current function"

        Mat open_img, closed_img;
        int morph_size = 2;

        // Create structuring element
        Mat element = getStructuringElement(MORPH_RECT, Size(2 * morph_size + 1, 2 * morph_size + 1), Point(morph_size, morph_size));

        morphologyEx(binary_image, closed_img, MORPH_CLOSE, element, Point(-1, -1), 1);
        morphologyEx(closed_img, open_img, MORPH_OPEN, element, Point(-1, -1), 1);

        open_img.convertTo(open_img, CV_32FC1);

        // For Erosion
        erode(open_img, open_img, element, Point(-1, -1), 1);
       
        // For Dilation
        dilate(open_img, open_img, element, Point(-1, -1), 1);

        //Yes, the same image was eroded and dilated.

        image_details << img_name << "," << src.cols << "," << src.rows << "\n";
    }

    image_details.close();

    return 0;
}

Код работает для всех файлов в папке и дает ожидаемые результаты, но он ищет файл «desktop.bmp» в каталоге, чего в идеале не должно быть. Вот фрагмент ошибки, с которой я столкнулся. Диалоговое окно вывода и вывод на терминал.

При нажатии «Повторить» это места, на которые указывает

  1. векторный файл в папке include
  2. Mat img_crop;
    img_crop = drawing(boundRect[1]);
    
    исходного кода (также добавленного в качестве комментариев в приведенном выше коде).

P.S.: Мой каталог OpenCV сохраняется непосредственно в C:, а код и папка с изображениями сохраняются на рабочем столе. Цикл for, который я использую, выглядит так for (const auto& dirEntry : directory_iterator(image_folder)). Я использую С++ 20

Какую помощь, по вашему мнению, смогут оказать люди, если вы не опубликуете код, который это делает?

Nathan Pierson 03.04.2023 07:56

Зачем компилятору изображение? Этого не произойдет, если только вы неправильно не настроите систему сборки, чтобы попытаться выполнить сборку с этим файлом. Вы уверены, что это запрашивает компилятор, а не ваша собственная программа? Какова фактическая ошибка, которую вы получаете? Если это настоящая ошибка сборки, скопируйте и вставьте (как текст!) Полный и полный журнал сборки в свой вопрос. Вместе со всей информацией, возможно, о вашей настройке сборки и системе. Пожалуйста отредактируйте свой вопрос, чтобы улучшить его.

Some programmer dude 03.04.2023 08:00

Ах, да, известная ошибка desktop.bmp, которая влияет на реализацию Microsoft библиотеки файловой системы до версии 11.4. Обновите среду выполнения. Очевидно, что предыдущее — не очень смешная шутка, но на ваш вопрос нельзя ответить по-другому. Либо вы сорвете джек-пот с какой-нибудь легко узнаваемой ошибкой, либо, что гораздо более вероятно, ваш вопрос останется без ответа. Если вам нужна помощь с кодом, вам нужно опубликовать код. Я нахожу удивительным, что некоторые постеры этого сайта не ценят этого.

john 03.04.2023 08:12

Извините, я не знал правил размещения вопроса здесь. Я должен был прочитать их раньше, моя ошибка. Я отредактировал свой вопрос, чтобы предоставить больше контекста. Спасибо за ваше терпение!

TheHiredGoon 03.04.2023 08:30

Вы найдете скрытый файл desktop.ini, так как вы не проверите расширение и не измените расширение на .bmp, вы столкнетесь с этой проблемой.

Alan Birtles 03.04.2023 08:38

IIRC есть способ сказать Windows не создавать эти desktop.ini файлы. Или, по крайней мере, не скрывать их, когда они там.

john 03.04.2023 08:39

Я не смог найти файлы desktop.ini в папке с изображениями или в папке, в которой сохранена моя программа. Я искал обновления, но мой VS 22 говорит, что он обновлен. Я что-то пропустил? Я установил свой VS 22 всего месяц назад. Я новичок в этом языке, поэтому мне нужно больше деталей (проще говоря). Спасибо за поддержку!

TheHiredGoon 03.04.2023 08:49

Смысл скрытых файлов в том, что вы не должны их видеть. Файл desktop.ini не имеет отношения к вашей среде разработки (VS22) или вашей программе, это обычное дело для Windows. Простой обходной путь — просто пропустить этот файл в цикле: if (dirEntry == "desktop.ini"){ continue; }

Some programmer dude 03.04.2023 08:55

Итак, нужно ли мне помнить об этом каждый раз, когда я работаю над кодом, который включает папки на рабочем столе, или это уникально для этой программы? Есть ли постоянное исправление этой ошибки? Кроме того, есть идеи, почему он ищет desktop.ini или desktop.bmp дважды?

TheHiredGoon 03.04.2023 08:59

Нет, Windows добавляет desktop.ini в качестве файла конфигурации, как проводник Windows должен отображать содержимое этого каталога. Ваш код заменяет .ini на .bmp (по неизвестным нам причинам), также ваш код дважды вызывает imread() для этого (по неизвестным нам причинам), поэтому не спрашивайте нас «почему». Вы должны задать этот вопрос от себя.

Öö Tiib 03.04.2023 09:26

простая отладка кода, то есть пошаговое его выполнение или печать некоторых переменных по мере его выполнения, должна была выявить проблему. Я не могу понять, как такой вопрос набрал пять голосов за такое короткое время!

Christoph Rackwitz 03.04.2023 11:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
11
108
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В этом коде:

for (const auto& dirEntry : directory_iterator(img_path))
{
    string img_name, path = get_stem(dirEntry);
    img_name = path;
    path = img_path + "\\" + img_name + ".bmp";

Вы отбрасываете расширение файла. Затем вы добавляете .bmp в качестве расширения. Если в каталоге есть файл, который не является файлом .bmp (например, в данном случае это скрытый файл desktop.ini), вы измените расширение имени файла на .bmp и попытаетесь открыть его, это явно не удастся (если нет оказывается .bmp с таким же именем).

Вы должны проверить расширение каждого файла в вашем коде, прежде чем продолжить. вы также должны убедиться, что запись на самом деле является файлом, а не каталогом. Я не уверен, почему вы делаете string img_name, path = get_stem(dirEntry); img_name = path;, а не просто string img_name = get_stem(dirEntry);?

Их исправление дает:

std::filesystem::path img_path = "C:\\Users\\TheHiredGoon\\Desktop\\image_folder"
for (const auto& dirEntry : directory_iterator(img_path))
{
    if (!dirEntry.is_regular_file() || dirEntry.path().extension() != ".bmp")
    {
        continue;
    }
    string img_name = get_stem(dirEntry);
    auto path = img_path / dirEntry.path();

Обратите внимание, что это будет принимать только .bmp, а не .Bmp или .BMP, если вы хотите исправить это, вы можете преобразовать расширение в нижний регистр или использовать boost::iequals.

Этот код сработал, спасибо за помощь. Нужно ли включать это условие if каждый раз, когда я работаю с изображениями (jpg, png и т. д.) в папке на рабочем столе? Я понимаю, что dirEntry.is_regular_file() кажется хорошей практикой для защиты кода от необычного поведения во время выполнения.

TheHiredGoon 03.04.2023 11:08

@TheHiredGoon Если вы хотите работать только с определенными расширениями файлов, то да, вам нужно убедиться, что расширение файла соответствует вашим ожиданиям. directory_iterator возвращает все файлы в папке, он не знает, что вы ожидаете только изображения

Alan Birtles 03.04.2023 11:21

@TheHiredGoon В общем, вы должны программировать более защищенно, вы не проверяете, что imread успешно, вы не проверяете, что boundRect содержит как минимум 2 элемента, прежде чем вызывать boundRect[1]. Чем больше проблем вы ожидаете и проверяете, тем меньше отладки вам придется делать, когда ваша программа неожиданно падает (надеюсь, она вообще не рухнет, а просто покажет значимое сообщение об ошибке)

Alan Birtles 03.04.2023 11:27

Другие вопросы по теме