Загрузка данных


#include "iostream"
#include "vector"
#include "fstream"
#include "string"
#include "windows.h" 
#include "GL/glut.h"

using namespace std;   

class Matrix {
public:
    int width;
    int height;
    vector<unsigned char> data;

    Matrix() : width(0), height(0) {}
    Matrix(int w, int h) : width(w), height(h), data(w * h, 0) {}

    bool fromBmp(const string& filePath) {
        ifstream file(filePath.c_str(), ios::binary);
        if (!file) return false;

        BITMAPFILEHEADER fileHeader;
        BITMAPINFOHEADER infoHeader;

        file.read(reinterpret_cast<char*>(&fileHeader), sizeof(fileHeader));
        file.read(reinterpret_cast<char*>(&infoHeader), sizeof(infoHeader));

        if (fileHeader.bfType != 0x4D42) return false; 

        width = infoHeader.biWidth;
        height = infoHeader.biHeight;
        data.assign(width * height, 0);

        file.seekg(fileHeader.bfOffBits, ios::beg);

        int bytesPerPixel = infoHeader.biBitCount / 8;
        int padding = (4 - (width * bytesPerPixel) % 4) % 4;

        if (infoHeader.biBitCount == 24) { 
            for (int y = 0; y < height; ++y) {
                for (int x = 0; x < width; ++x) {
                    unsigned char bgr[3];
                    file.read(reinterpret_cast<char*>(bgr), 3);
                    data[y * width + x] = static_cast<unsigned char>(0.299f * bgr[2] + 0.587f * bgr[1] + 0.114f * bgr[0]);
                }
                file.seekg(padding, ios::cur);
            }
        } else if (infoHeader.biBitCount == 8) { 
            for (int y = 0; y < height; ++y) {
                file.read(reinterpret_cast<char*>(&data[y * width]), width);
                file.seekg(padding, ios::cur);
            }
        }
        file.close();

        vector<unsigned char> flipped(width * height);
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                flipped[(height - 1 - y) * width + x] = data[y * width + x];
            }
        }
        data = flipped;

        return true;
    }
};

Matrix imgOriginal;
Matrix imgBinary;
Matrix imgDilated; // Заменено с imgEroded
Matrix imgEdges;

Matrix binarizeMatrix(const Matrix& matrix, unsigned char threshold = 127) {
    Matrix res(matrix.width, matrix.height);
    for (int i = 0; i < matrix.width * matrix.height; ++i) {
        res.data[i] = (matrix.data[i] >= threshold) ? 255 : 0;
    }
    return res;
}

/* =========================================================================
   АЛГОРИТМ МОРФОЛОГИЧЕСКОЙ ДИЛАТАЦИИ СТРУКТУРНЫМ ЭЛЕМЕНТОМ 3X3 ИЗ ЕДИНИЦ
   Реализует операцию логического "ИЛИ" (пиксель становится белым, 
   если в его окрестности 3х3 есть хотя бы один белый пиксель).
   ========================================================================= */
Matrix dilateMatrix(const Matrix& matrix) {
    Matrix res(matrix.width, matrix.height);

    for (int y = 1; y < matrix.height - 1; ++y) {
        for (int x = 1; x < matrix.width - 1; ++x) {
            bool anyWhite = false;
            
            // Наложение квадратного структурного элемента 3х3
            for (int ky = -1; ky <= 1; ++ky) {
                for (int kx = -1; kx <= 1; ++kx) {
                    if (matrix.data[(y + ky) * matrix.width + (x + kx)] == 255) {
                        anyWhite = true;
                        break;
                    }
                }
                if (anyWhite) break;
            }
            // Пиксель становится белым при наличии хоть одного белого соседа
            res.data[y * matrix.width + x] = anyWhite ? 255 : 0;
        }
    }
    return res;
}

/* =========================================================================
   ВЫДЕЛЕНИЕ ВНЕШНИХ ГРАНИЦ НА ОСНОВЕ ОПЕРАЦИИ XOR
   Edges = Binary XOR Dilated. Оставляет только расширившуюся часть объектов.
   ========================================================================= */
Matrix findEdgesXor(const Matrix& binary, const Matrix& dilated) {
    Matrix res(binary.width, binary.height);
    for (int i = 0; i < binary.width * binary.height; ++i) {
        res.data[i] = binary.data[i] ^ dilated.data[i]; 
    }
    return res;
}

void drawImageQuad(const Matrix& matrix, int xOffset, int yOffset, int quadW, int quadH) {
    glViewport(xOffset, yOffset, quadW, quadH);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, matrix.width, 0, matrix.height, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    glRasterPos2i(0, 0);
    glDrawPixels(matrix.width, matrix.height, GL_LUMINANCE, GL_UNSIGNED_BYTE, &matrix.data[0]);
}

void display() {
    glClear(GL_COLOR_BUFFER_BIT);

    int windowW = glutGet(GLUT_WINDOW_WIDTH);
    int windowH = glutGet(GLUT_WINDOW_HEIGHT);
    int quadW = windowW / 2;
    int quadH = windowH / 2;

    drawImageQuad(imgOriginal, 0, quadH, quadW, quadH); 
    drawImageQuad(imgBinary, quadW, quadH, quadW, quadH); 
    drawImageQuad(imgDilated, 0, 0, quadW, quadH); // Отображение дилатации в левом нижнем углу
    drawImageQuad(imgEdges, quadW, 0, quadW, quadH);     

    glutSwapBuffers();
}

int main(int argc, char** argv) {
    if (!imgOriginal.fromBmp("lena1_1.bmp")) {
        cout << "Error: Cannot open 'lena1_1.bmp'. Check file path!" << endl;
        system("pause");
        return -1;
    }

    imgBinary = binarizeMatrix(imgOriginal, 127);
    imgDilated = dilateMatrix(imgBinary); // Заменено на дилатацию
    imgEdges  = findEdgesXor(imgBinary, imgDilated);

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(imgOriginal.width * 2, imgOriginal.height * 2);
    glutCreateWindow("Laboratory 7: C++ Image Processing (Dilation & XOR Borders)");

    glClearColor(0.15f, 0.15f, 0.15f, 1.0f);
    glutDisplayFunc(display);

    cout << "OpenGL Window opened successfully. Close window to exit." << endl;
    glutMainLoop();

    return 0;
}