#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;
}