Реализация фильтров

This commit is contained in:
Евгений Титаренко 2024-04-19 21:17:03 +03:00
parent 24e2cbb354
commit 3fe2a87e35
4 changed files with 109 additions and 58 deletions

View file

@ -1,4 +1,6 @@
#include <cmath> #include <cmath>
#include <memory>
#include <algorithm>
#include "bmpimage.h" #include "bmpimage.h"
BMPImage::BMPImage(const BitmapFileHeader &fileHeader, const BITMAPINFOHEADER &infoHeader, const PixelArray &pixelArray) BMPImage::BMPImage(const BitmapFileHeader &fileHeader, const BITMAPINFOHEADER &infoHeader, const PixelArray &pixelArray)
@ -83,6 +85,7 @@ BMPImage BMPImage::appendRight(BMPImage &img) {
uint32_t newWidth = this->infoHeader.BitmapWidth + img.width(); uint32_t newWidth = this->infoHeader.BitmapWidth + img.width();
// Pixel **newPixelArray; // Pixel **newPixelArray;
PixelArray newPixelArray(newWidth, newHeight); PixelArray newPixelArray(newWidth, newHeight);
// std::shared_ptr<PixelArray> newPixelArray = std::make_shared<PixelArray>(newWidth, newHeight);
// newPixelArray = new Pixel *[newHeight]; // newPixelArray = new Pixel *[newHeight];
for (int i = 0; i < this->infoHeader.BitmapHeight; ++i) { for (int i = 0; i < this->infoHeader.BitmapHeight; ++i) {
// newPixelArray[i] = new Pixel[newWidth]; // newPixelArray[i] = new Pixel[newWidth];
@ -105,6 +108,32 @@ BMPImage BMPImage::overlay(BMPImage &img, uint32_t pos_x, uint32_t pos_y) {
return {pixels}; return {pixels};
} }
BMPImage BMPImage::applyFilter(const std::function<uint8_t(std::array<int, 9> &)> &filter) {
auto origPixels = this->pixels_copy();
PixelArray pixels(this->width(), this->height());
for (int y = 1; y < this->height() - 1; ++y) {
for (int x = 1; x < this->width() - 1; ++x) {
auto p1 = origPixels(y - 1, x - 1);
auto p2 = origPixels(y - 1, x);
auto p3 = origPixels(y - 1, x + 1);
auto p4 = origPixels(y, x - 1);
auto p5 = origPixels(y, x);
auto p6 = origPixels(y, x + 1);
auto p7 = origPixels(y + 1, x - 1);
auto p8 = origPixels(y + 1, x);
auto p9 = origPixels(y + 1, x + 1);
std::array<int, 9> red_channel = {p1.r, p2.r, p3.r, p4.r, p5.r, p6.r, p7.r, p8.r, p9.r};
std::array<int, 9> green_channel = {p1.g, p2.g, p3.g, p4.g, p5.g, p6.g, p7.g, p8.g, p9.g};
std::array<int, 9> blue_channel = {p1.b, p2.b, p3.b, p4.b, p5.b, p6.b, p7.b, p8.b, p9.b};
auto r = filter(red_channel);
auto g = filter(green_channel);
auto b = filter(blue_channel);
pixels(y, x) = {r, g, b};
}
}
return {pixels};
}
BMPImage readBMPImage(const std::string &filename) { BMPImage readBMPImage(const std::string &filename) {
BitmapFileHeader bitmapFileHeader; BitmapFileHeader bitmapFileHeader;
@ -405,30 +434,39 @@ BMPImage upscale2x_ver2(BMPImage &img) {
return {newPixelArray}; return {newPixelArray};
} }
BMPImage filter(BMPImage &img, int mask[9], uint8_t modifier) { uint8_t medianFilter(std::array<int, 9> &pixels) {
auto origPixels = img.pixels_copy(); std::sort(pixels.begin(), pixels.end());
PixelArray pixels(img.width(), img.height()); return ui8_clamp(pixels[5]);
for (int y = 1; y < img.height() - 1; ++y) { }
for (int x = 1; x < img.width() - 1; ++x) {
auto p1 = origPixels(y - 1, x - 1); uint8_t averageFilter(std::array<int, 9> &pixels) {
auto p2 = origPixels(y - 1, x); return ui8_clamp((pixels[0] * AVERAGE_MASK[0] + pixels[1] * AVERAGE_MASK[1] + pixels[2] * AVERAGE_MASK[2] +
auto p3 = origPixels(y - 1, x + 1); pixels[3] * AVERAGE_MASK[3] + pixels[4] * AVERAGE_MASK[4] + pixels[5] * AVERAGE_MASK[5] +
auto p4 = origPixels(y, x - 1); pixels[6] * AVERAGE_MASK[6] + pixels[7] * AVERAGE_MASK[7] + pixels[8] * AVERAGE_MASK[8]) / 9);
auto p5 = origPixels(y, x); }
auto p6 = origPixels(y, x + 1);
auto p7 = origPixels(y + 1, x - 1); uint8_t prewittDXFilter(std::array<int, 9> &pixels) {
auto p8 = origPixels(y + 1, x); return ui8_clamp(pixels[0] * PREWITT_MASK_DX[0] + pixels[1] * PREWITT_MASK_DX[1] + pixels[2] * PREWITT_MASK_DX[2] +
auto p9 = origPixels(y + 1, x + 1); pixels[3] * PREWITT_MASK_DX[3] + pixels[4] * PREWITT_MASK_DX[4] + pixels[5] * PREWITT_MASK_DX[5] +
auto r = p1.r * mask[0] + p2.r * mask[1] + p3.r * mask[2] + p4.r * mask[3] + p5.r * mask[4] + pixels[6] * PREWITT_MASK_DX[6] + pixels[7] * PREWITT_MASK_DX[7] + pixels[8] * PREWITT_MASK_DX[8]);
p6.r * mask[5] + p7.r * mask[6] + p8.r * mask[7] + p9.r * mask[8]; }
auto g = p1.g * mask[0] + p2.g * mask[1] + p3.g * mask[2] + p4.g * mask[3] + p5.g * mask[4] +
p6.g * mask[5] + p7.g * mask[6] + p8.g * mask[7] + p9.g * mask[8]; uint8_t prewittDYFilter(std::array<int, 9> &pixels) {
auto b = p1.b * mask[0] + p2.b * mask[1] + p3.b * mask[2] + p4.b * mask[3] + p5.b * mask[4] + return ui8_clamp(pixels[0] * PREWITT_MASK_DY[0] + pixels[1] * PREWITT_MASK_DY[1] + pixels[2] * PREWITT_MASK_DY[2] +
p6.b * mask[5] + p7.b * mask[6] + p8.b * mask[7] + p9.b * mask[8]; pixels[3] * PREWITT_MASK_DY[3] + pixels[4] * PREWITT_MASK_DY[4] + pixels[5] * PREWITT_MASK_DY[5] +
pixels(y, x) = {ui8_clamp(r / modifier), ui8_clamp(g / modifier), ui8_clamp(b / modifier)}; pixels[6] * PREWITT_MASK_DY[6] + pixels[7] * PREWITT_MASK_DY[7] + pixels[8] * PREWITT_MASK_DY[8]);
} }
}
return {pixels}; uint8_t sobelDXFilter(std::array<int, 9> &pixels) {
return ui8_clamp(pixels[0] * SOBEL_MASK_DX[0] + pixels[1] * SOBEL_MASK_DX[1] + pixels[2] * SOBEL_MASK_DX[2] +
pixels[3] * SOBEL_MASK_DX[3] + pixels[4] * SOBEL_MASK_DX[4] + pixels[5] * SOBEL_MASK_DX[5] +
pixels[6] * SOBEL_MASK_DX[6] + pixels[7] * SOBEL_MASK_DX[7] + pixels[8] * SOBEL_MASK_DX[8]);
}
uint8_t sobelDYFilter(std::array<int, 9> &pixels) {
return ui8_clamp(pixels[0] * SOBEL_MASK_DY[0] + pixels[1] * SOBEL_MASK_DY[1] + pixels[2] * SOBEL_MASK_DY[2] +
pixels[3] * SOBEL_MASK_DY[3] + pixels[4] * SOBEL_MASK_DY[4] + pixels[5] * SOBEL_MASK_DY[5] +
pixels[6] * SOBEL_MASK_DY[6] + pixels[7] * SOBEL_MASK_DY[7] + pixels[8] * SOBEL_MASK_DY[8]);
} }
PixelArray::PixelArray(uint32_t width, uint32_t height) { PixelArray::PixelArray(uint32_t width, uint32_t height) {

View file

@ -3,9 +3,17 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <fstream> #include <fstream>
#include <array>
#include <functional>
#include "psf.h" #include "psf.h"
const char PADDING_ZEROES[3] = {0, 0, 0}; const char PADDING_ZEROES[3] = {0, 0, 0};
const int AVERAGE_MASK[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
const int PREWITT_MASK_DX[9] = {-1, 0, 1, -1, 0, 1, -1, 0, 1};
const int PREWITT_MASK_DY[9] = {-1, -1, -1, 0, 0, 0, 1, 1, 1};
const int SOBEL_MASK_DX[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};
const int SOBEL_MASK_DY[9] = {-1, -2, -1, 0, 0, 0, 1, 2, 1};
#pragma pack(push, 1) #pragma pack(push, 1)
struct BitmapFileHeader { struct BitmapFileHeader {
@ -91,6 +99,8 @@ public:
BMPImage appendRight(BMPImage &); BMPImage appendRight(BMPImage &);
BMPImage overlay(BMPImage &, uint32_t, uint32_t); BMPImage overlay(BMPImage &, uint32_t, uint32_t);
BMPImage applyFilter(const std::function<uint8_t (std::array<int,9>&)>& filter);
}; };
BMPImage readBMPImage(const std::string &filename); BMPImage readBMPImage(const std::string &filename);
@ -126,4 +136,14 @@ BMPImage textImg(const std::u16string &, Font *font, uint8_t scale = 1, Pixel ba
uint8_t ui8_clamp(int value, uint8_t min = 0, uint8_t max = 255); uint8_t ui8_clamp(int value, uint8_t min = 0, uint8_t max = 255);
BMPImage filter(BMPImage &img, int mask[9], uint8_t modifier = 9); uint8_t medianFilter(std::array<int, 9> &);
uint8_t averageFilter(std::array<int, 9> &);
uint8_t prewittDXFilter(std::array<int, 9> &);
uint8_t prewittDYFilter(std::array<int, 9> &);
uint8_t sobelDXFilter(std::array<int, 9> &);
uint8_t sobelDYFilter(std::array<int, 9> &);

View file

@ -2,11 +2,8 @@
#include "bmpimage.h" #include "bmpimage.h"
#include "psf.h" #include "psf.h"
const std::string FILENAME = "../elef.bmp";
const std::string FILENAME_OUT = "../elef_out.bmp";
auto font = readPSF("../fonts/ruscii_8x16_2.psf"); auto font = readPSF("../fonts/ruscii_8x16_2.psf");
//
void lab01() { void lab01() {
auto og_image = readBMPImage("../elef.bmp"); auto og_image = readBMPImage("../elef.bmp");
auto pixels1 = og_image.pixels_copy(); auto pixels1 = og_image.pixels_copy();
@ -31,7 +28,6 @@ void lab01() {
orig_text, 0, 0).save("../lab01/elef1.bmp"); orig_text, 0, 0).save("../lab01/elef1.bmp");
} }
//
void lab02_01() { void lab02_01() {
auto img = readBMPImage("../tea.bmp"); auto img = readBMPImage("../tea.bmp");
auto text1024 = textImg(u"1024", &font, 3); auto text1024 = textImg(u"1024", &font, 3);
@ -63,7 +59,6 @@ void lab02_01() {
// newImg2->save("../lab02/tea_upscale.bmp"); // newImg2->save("../lab02/tea_upscale.bmp");
} }
//
void lab02_02() { void lab02_02() {
auto img = readBMPImage("../tea.bmp"); auto img = readBMPImage("../tea.bmp");
auto ogText = textImg(u"Оригинал", &font, 3); auto ogText = textImg(u"Оригинал", &font, 3);
@ -103,7 +98,6 @@ void lab02_02() {
gsImg64).appendRight(gsImg32).save("../lab02/tea_grayscale.bmp"); gsImg64).appendRight(gsImg32).save("../lab02/tea_grayscale.bmp");
} }
//
void lab02_03() { void lab02_03() {
auto img = readBMPImage("../tea.bmp"); auto img = readBMPImage("../tea.bmp");
auto text = textImg(u"Оригинал", &font, 3); auto text = textImg(u"Оригинал", &font, 3);
@ -134,40 +128,39 @@ void lab02_03() {
} }
void lab03() { void lab03() {
auto img = readBMPImage("../tea.bmp"); auto img = readBMPImage("../bike.bmp");
auto imgGS = grayscale(img); auto imgGS = grayscale(img);
int avrg_mask[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
int previtt_mask1[9] = {-1, 0, 1, -1, 0, 1, -1, 0, 1};
int previtt_mask2[9] = {-1, -1, -1, 0, 0, 0, 1, 1, 1};
int sobel_mask1[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};
int sobel_mask2[9] = {-1, -2, -1, 0, 0, 0, 1, 2, 1};
auto avrg_text = textImg(u"Осреднение", &font, 3); auto avrg_text = textImg(u"Осреднение", &font, 3);
auto previtt_text = textImg(u"Фильтр Превитта", &font, 3); auto median_text = textImg(u"Медиана", &font, 3);
auto prewitt_text = textImg(u"Фильтр Превитта", &font, 3);
auto sobel_text = textImg(u"Фильтр Собеля", &font, 3); auto sobel_text = textImg(u"Фильтр Собеля", &font, 3);
auto text = textImg(u"Оригинал", &font, 3); auto text = textImg(u"Оригинал", &font, 3);
auto avrg_image = filter(imgGS, avrg_mask).overlay(avrg_text, 0, 0);
auto previtt_image1 = filter(imgGS, previtt_mask1, 1);//.overlay(previtt_text, 0, 0); auto avrg_image = imgGS.applyFilter(averageFilter).overlay(avrg_text, 0, 0);
auto previtt_image2 = filter(imgGS, previtt_mask2, 1);//.overlay(previtt_text, 0, 0); auto median_image = imgGS.applyFilter(medianFilter).overlay(median_text, 0, 0);
previtt_image1.save("../lab03/previtt1.bmp"); auto prewitt_dx_image = imgGS.applyFilter(prewittDXFilter);
previtt_image2.save("../lab03/previtt2.bmp"); auto prewitt_dy_image = imgGS.applyFilter(prewittDYFilter);
PixelArray previttPixels(previtt_image1.width(), previtt_image1.height()); prewitt_dx_image.save("../lab03/prewitt1.bmp");
for (int y = 0; y < previtt_image1.height(); ++y) { prewitt_dy_image.save("../lab03/prewitt2.bmp");
for (int x = 0; x < previtt_image1.width(); ++x) { PixelArray prewittPixels(prewitt_dx_image.width(), prewitt_dy_image.height());
previttPixels(y, x) = previtt_image1.pixels()(y, x) + previtt_image2.pixels()(y, x); for (int y = 0; y < prewitt_dx_image.height(); ++y) {
for (int x = 0; x < prewitt_dx_image.width(); ++x) {
prewittPixels(y, x) = prewitt_dx_image.pixels()(y, x) + prewitt_dy_image.pixels()(y, x);
} }
} }
auto previtt_image = BMPImage(previttPixels).overlay(previtt_text, 0, 0); auto prewitt_image = BMPImage(prewittPixels).overlay(prewitt_text, 0, 0);
auto sobel_image1 = filter(imgGS, sobel_mask1, 1).overlay(sobel_text, 0, 0); auto sobel_dx_image = imgGS.applyFilter(sobelDXFilter).overlay(sobel_text, 0, 0);
auto sobel_image2 = filter(imgGS, sobel_mask2, 1).overlay(sobel_text, 0, 0); auto sobel_dy_image2 = imgGS.applyFilter(sobelDYFilter).overlay(sobel_text, 0, 0);
PixelArray sobelPixels(sobel_image1.width(), sobel_image2.height()); PixelArray sobelPixels(sobel_dx_image.width(), sobel_dx_image.height());
for (int y = 0; y < sobel_image1.height(); ++y) { for (int y = 0; y < sobel_dx_image.height(); ++y) {
for (int x = 0; x < sobel_image1.width(); ++x) { for (int x = 0; x < sobel_dx_image.width(); ++x) {
previttPixels(y, x) = sobel_image1.pixels()(y, x) + sobel_image2.pixels()(y, x); sobelPixels(y, x) = sobel_dx_image.pixels()(y, x) + sobel_dy_image2.pixels()(y, x);
} }
} }
auto sobel_image = BMPImage(previttPixels).overlay(sobel_text, 0, 0); auto sobel_image = BMPImage(sobelPixels).overlay(sobel_text, 0, 0);
imgGS.overlay(text, 0, 0).appendRight(avrg_image).save("../lab03/avrg_filter.bmp"); imgGS.overlay(text, 0, 0).appendRight(avrg_image).appendRight(median_image).save("../lab03/avrg_median_filter.bmp");
imgGS.overlay(text, 0, 0).appendRight(previtt_image).save("../lab03/previtt_filter.bmp"); imgGS.overlay(text, 0, 0).appendRight(prewitt_image).save("../lab03/prewitt_filter.bmp");
imgGS.overlay(text, 0, 0).appendRight(sobel_image).save("../lab03/sobel_filter.bmp"); imgGS.overlay(text, 0, 0).appendRight(sobel_image).save("../lab03/sobel_filter.bmp");
} }

View file

@ -49,7 +49,7 @@ Font readPSF(const std::string &filename) {
if (curByte != 0xFF) { if (curByte != 0xFF) {
vectorOfBytes.push_back(curByte); vectorOfBytes.push_back(curByte);
} else { } else {
unsigned long long int bytesCount = vectorOfBytes.size(); auto bytesCount = vectorOfBytes.size();
unsigned char bytes[bytesCount]; unsigned char bytes[bytesCount];
for (int i = 0; i < bytesCount; ++i) { for (int i = 0; i < bytesCount; ++i) {
bytes[i] = vectorOfBytes[i]; bytes[i] = vectorOfBytes[i];