Загрузка данных
#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;
}