• Не могу понять, почему у выходного файла идет смещение и ухудшение качества картинки?

    @Leroi_1 Автор вопроса
    Wataru, Сделал, как ты сказал, но ничего не поменялось
    Написано
  • Не могу понять, почему у выходного файла идет смещение и ухудшение качества картинки?

    @Leroi_1 Автор вопроса
    Wataru, Я со вчерашнего дня сижу и не совсем понимаю, где именно ты имеешь ввиду "исходное изображение расширить хотя бы на 7 байт в конце, чтобы не было чтения за границей массива, а ваше ядро добить тремя 0 до ширины в 8 байт." Качество самой картинки, в принципе, меня устраивает, но не смещение остается. Для понимания прикреплю вводное и выводное изображения. (Черное вводное)
    6692a7fb63674656133483.jpeg
    6692a8061bc1c047780453.jpeg
    Написано
  • Не могу понять, почему у выходного файла идет смещение и ухудшение качества картинки?

    @Leroi_1 Автор вопроса
    Я умножения на 8 почистил, но не понимаю, как избавиться от циклов от -2 до 2.
    Качество изображения стало лучше!
    #include <arm_neon.h>
    #include <vector>
    #include <fstream>
    #include <stdexcept>
    #include <chrono>
    #include <iostream>
    #include <opencv2/core.hpp>
    #include <opencv2/imgcodecs.hpp>
    #include <opencv2/imgproc.hpp>
    #include <cstdint>
    
    namespace bmp {
    
    // Перечисление для поддержки различных форматов заголовков BMP
    enum class InfoHeaderFormats {
        InfoHeader
        // Другие форматы могут быть добавлены здесь
    };
    
    // Класс для работы с BMP-файлами
    template <InfoHeaderFormats T>
    class BMPFileUserDefined {
    public:
        // Конструктор
        BMPFileUserDefined() {}
    
        // Метод для чтения BMP-файла
        void read_bmp(const std::string& filename, int& width, int& height, std::vector<uint8_t>& pixelData) {
            std::ifstream file(filename, std::ios::binary);
            if (!file) {
                throw std::runtime_error("Не удалось открыть файл для чтения");
            }
    
            // Здесь должен быть код для чтения заголовка BMP-файла и заполнения переменных width, height и pixelData
    
            // Пример чтения данных (заглушка)
            width = 384; // Пример ширины
            height = 384; // Пример высоты
            pixelData.resize(width * height);
            file.read(reinterpret_cast<char*>(pixelData.data()), pixelData.size());
    
            if (!file) {
                throw std::runtime_error("Ошибка при чтении файла");
            }
        }
    
        // Метод для создания BMP-файла
        void create_bmp(const std::string& filename, int width, int height, const uint8_t* data) {
            std::ofstream file(filename, std::ios::binary);
            if (!file) {
                throw std::runtime_error("Не удалось открыть файл для записи");
            }
    
            // Здесь должен быть код для записи заголовка BMP-файла
    
            // Запись пиксельных данных
            file.write(reinterpret_cast<const char*>(data), width * height);
    
            if (!file.good()) {
                throw std::runtime_error("Ошибка при записи файла");
            }
        }
    
        // Деструктор
        ~BMPFileUserDefined() {}
    
    private:
        // Частные методы и члены класса
    };
    
    } // namespace bmp
    
    // Функция для изменения размера изображения
    void resizeImage(cv::Mat &image) {
        // Устанавливаем новый размер в два раза больше исходного
        cv::Size newSize(image.cols * 2, image.rows * 2);
        cv::Mat resizedImage;
    
        // Изменяем размер изображения
        cv::resize(image, resizedImage, newSize, 0, 0, cv::INTER_LINEAR);
    
        // Обновляем исходное изображение
        image = resizedImage;
    }
    
    // Функция свёртки с использованием NEON интринсиков
    void convolve_neon(const uint8_t* input, int width, int height, uint8_t* output) {
        // Определяем фильтр свёртки
        const int8_t kernel[25] = {
            1, 1, 1, 1, 1,
            1, 1, 1, 1, 1,
            0, 0, 0, 0, 0,
            -1,-1,-1,-1,-1,
            -1,-1,-1,-1,-1
        };
    
        // Пример реализации свёртки с использованием NEON интринсиков
        
        // Предполагается, что input и output выровнены по 16 байт
        for (int y = 2; y < height - 2; ++y) {
            for (int x = 2; x < width - 2; ++x) {
                int32x4_t sum = vdupq_n_s32(0);
    
                for (int ky = -2; ky <= 2; ++ky) {
                    for (int kx = -2; ++kx) {
                        // Получаем значение пикселя и ядра
                        int pixel_value = input[(y + ky) * width + (x + kx)];
                        int kernel_value = kernel[(ky + 2) * 5 + (kx + 2)];
    
                        // Умножаем и добавляем к сумме
                        sum = vmlaq_n_s32(sum, vdupq_n_s32(pixel_value), kernel_value);
                    }
                }
    
                // Сохраняем результат в выходном массиве
                int32_t result = vgetq_lane_s32(vaddq_s32(sum, vdupq_n_s32(128)), 0);
                output[y * width + x] = static_cast<uint8_t>(std::max(0, std::min(255, result)));
            }
        }
    }
    
    // Функция для применения фильтра Гаусса
    void applyGaussianBlur(cv::Mat &image) {
        // Размытие Гаусса с ядром 5x5
        cv::GaussianBlur(image, image, cv::Size(5, 5), 0);
    }
    
    // Функция для применения порогового фильтра
    void applyThreshold(cv::Mat &image) {
        // Пороговая обработка
        cv::threshold(image, image, 255, 255, cv::THRESH_BINARY);
    }
    
    // Функция для обнаружения краев с помощью оператора Собеля
    void detectEdgesSobel(cv::Mat &image) {
        cv::Mat grad_x, grad_y;
        cv::Mat abs_grad_x, abs_grad_y;
    
        // Вычисление производных по X и Y
        cv::Sobel(image, grad_x, CV_16S, 1, 0, 3);
        cv::Sobel(image, grad_y, CV_16S, 0, 1, 3);
    
        // Преобразование в абсолютные значения
        cv::convertScaleAbs(grad_x, abs_grad_x);
        cv::convertScaleAbs(grad_y, abs_grad_y);
    
        // Объединение градиентов
        cv::addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, image);
    }
    
    int main() {
        try {
            // Используем класс BMPFileUserDefined для чтения BMP-файла
            bmp::BMPFileUserDefined<bmp::InfoHeaderFormats::InfoHeader> bmpFile;
            std::vector<uint8_t> pixelData;
            int width, height;
            bmpFile.read_bmp("Scene384/0100.bmp", width, height, pixelData);
    
            // Проверяем, что данные изображения загружены корректно
            if (pixelData.empty()) {
                throw std::runtime_error("Ошибка: данные изображения не загружены");
            }
    
            // Преобразуем пиксельные данные в объект cv::Mat
            cv::Mat image(height, width, CV_8UC1, pixelData.data());
    
            // Проверяем, что объект cv::Mat инициализирован корректно
            if (image.empty()) {
                throw std::runtime_error("Ошибка: объект cv::Mat не инициализирован");
            }
    
            // Применяем функции обработки изображений
            resizeImage(image);
            applyGaussianBlur(image);
            applyThreshold(image);
            detectEdgesSobel(image);
    
            // После обработки преобразуем данные обратно и сохраняем BMP-файл
            bmpFile.create_bmp("res_arm.bmp", image.cols, image.rows, image.data);
    
            // Выводим сообщение об успешном сохранении файла
            std::cout << "Файл успешно сохранен как res_arm.bmp" << std::endl;
        } catch (const std::exception &e) {
            std::cerr << "Error: " << e.what() << std::endl;
            return 1;
        }
    
        return 0;
    }
    Написано