diff --git a/bmpimage.cpp b/bmpimage.cpp index b64baaa..b2ba7ec 100644 --- a/bmpimage.cpp +++ b/bmpimage.cpp @@ -1,3 +1,4 @@ +#include #include "bmpimage.h" BMPImage::BMPImage(const BitmapFileHeader &fileHeader, const BITMAPINFOHEADER &infoHeader, const PixelArray &pixelArray) @@ -149,9 +150,9 @@ BMPImage readBMPImage(const std::string &filename) { } Pixel operator+(const Pixel &p1, const Pixel &p2) { - const uint8_t r = p1.r + p2.r; - const uint8_t g = p1.g + p2.g; - const uint8_t b = p1.b + p2.b; + const uint8_t r = ui8_clamp((int) p1.r + p2.r); + const uint8_t g = ui8_clamp((int) p1.g + p2.g); + const uint8_t b = ui8_clamp((int) p1.b + p2.b); return {r, g, b}; } @@ -284,7 +285,6 @@ BMPImage upscale1_5x(BMPImage &img) { } } return {newPixelArray}; - } BMPImage textImg(const std::u16string &str, Font *font, uint8_t scale, Pixel background_color, Pixel font_color) { @@ -309,6 +309,128 @@ BMPImage textImg(const std::u16string &str, Font *font, uint8_t scale, Pixel bac return {pixels}; } +BMPImage upscale1_5x_ver2(BMPImage &img) { + auto oldPixels = img.pixels(); + const uint32_t newHeight = img.height() * 3 / 2; + const uint32_t newWidth = img.width() * 3 / 2; + PixelArray newPixelArray(newWidth, newHeight); + for (int i = 0; i < newHeight; ++i) { + int oldi = std::round(i * 2 / 3.); + if ((i + 1) % 3 == 0) { + if (i == newHeight - 1) + newPixelArray(i, 0) = oldPixels(oldi, 0) / 2; + else { + newPixelArray(i, 0) = oldPixels(oldi, 0) / 2 + oldPixels(oldi + 1, 0) / 2; + } + continue; + } + for (int j = 0; j < newWidth; ++j) { + int oldj = std::round(j * 2 / 3.); + if ((j + 1) % 3 != 0) + newPixelArray(i, j) = oldPixels(oldi, oldj); + else if (j == newWidth - 1) + newPixelArray(i, j) = oldPixels(oldi, oldj) / 2; + else + newPixelArray(i, j) = oldPixels(oldi, oldj) / 2 + oldPixels(oldi, oldj + 1) / 2; + } + } + for (int i = 2; i < newHeight; i += 3) { + if (i == newHeight - 1) + for (int j = 0; j < newWidth; ++j) { + newPixelArray(i, j) = newPixelArray(i - 1, j) / 2; + } + else + for (int j = 1; j < newWidth; ++j) { + if (j == newWidth - 1) { + newPixelArray(i, j) = newPixelArray(i, j - 1) / 2; + continue; + } + auto f00 = newPixelArray(i - 1, j - 1); + auto f10 = newPixelArray(i - 1, j + 1); + auto f01 = newPixelArray(i + 1, j - 1); + auto f11 = newPixelArray(i + 1, j + 1); + newPixelArray(i, j) = f10 / 4 + f00 / 4 + f01 / 4 + f11 / 4; + } + } + return {newPixelArray}; +} + +Pixel operator-(const Pixel &p1, const Pixel &p2) { + auto r = ui8_clamp((int) p1.r - p2.r); + auto g = ui8_clamp((int) p1.g - p2.g); + auto b = ui8_clamp((int) p1.b - p2.b); + return {r, g, b}; +} + +BMPImage upscale2x_ver2(BMPImage &img) { + auto oldPixels = img.pixels(); + const uint32_t newHeight = img.height() * 2; + const uint32_t newWidth = img.width() * 2; + PixelArray newPixelArray(newWidth, newHeight); + for (int i = 0; i < newHeight; ++i) { + if ((i + 1) % 2 == 0) { + if (i == newHeight - 1) + newPixelArray(i, 0) = oldPixels(i / 2, 0) / 2; + else + newPixelArray(i, 0) = oldPixels(i / 2, 0) / 2 + oldPixels(i / 2 + 1, 0) / 2; + continue; + } + for (int j = 0; j < newWidth; ++j) { + if (j % 2 == 0) + newPixelArray(i, j) = oldPixels(i / 2, j / 2); + else if (j == newWidth - 1) + newPixelArray(i, j) = oldPixels(i / 2, j / 2) / 2; + else + newPixelArray(i, j) = oldPixels(i / 2, j / 2) / 2 + oldPixels(i / 2, j / 2 + 1) / 2; + } + } + for (int i = 1; i < newHeight; i += 2) { + if (i == newHeight - 1) + for (int j = 1; j < newWidth; ++j) { + newPixelArray(i, j) = newPixelArray(i - 1, j) / 2; + } + else + for (int j = 1; j < newWidth; ++j) { + if (j == newWidth - 1) { + newPixelArray(i, j) = newPixelArray(i, j - 1) / 2; + continue; + } + auto f00 = newPixelArray(i - 1, j - 1); + auto f10 = newPixelArray(i - 1, j + 1); + auto f01 = newPixelArray(i + 1, j - 1); + auto f11 = newPixelArray(i + 1, j + 1); + newPixelArray(i, j) = f10 / 4 + f00 / 4 + f01 / 4 + f11 / 4; + } + } + return {newPixelArray}; +} + +BMPImage filter(BMPImage &img, int mask[9], uint8_t modifier) { + auto origPixels = img.pixels_copy(); + PixelArray pixels(img.width(), img.height()); + 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); + 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); + auto r = p1.r * mask[0] + p2.r * mask[1] + p3.r * mask[2] + p4.r * mask[3] + p5.r * mask[4] + + 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]; + auto b = p1.b * mask[0] + p2.b * mask[1] + p3.b * mask[2] + p4.b * mask[3] + p5.b * mask[4] + + p6.b * mask[5] + p7.b * mask[6] + p8.b * mask[7] + p9.b * mask[8]; + pixels(y, x) = {ui8_clamp(r / modifier), ui8_clamp(g / modifier), ui8_clamp(b / modifier)}; + } + } + return {pixels}; +} + PixelArray::PixelArray(uint32_t width, uint32_t height) { this->_width = width; this->_height = height; diff --git a/bmpimage.h b/bmpimage.h index add6396..77de907 100644 --- a/bmpimage.h +++ b/bmpimage.h @@ -105,6 +105,8 @@ Pixel operator-(const Pixel &, const uint8_t &); Pixel operator-(const uint8_t &, const Pixel &); +Pixel operator-(const Pixel &, const Pixel &); + BMPImage grayscale(BMPImage &); BMPImage invertColors(BMPImage &); @@ -115,7 +117,13 @@ BMPImage downscale2x(BMPImage &); BMPImage upscale1_5x(BMPImage &); +BMPImage upscale1_5x_ver2(BMPImage &); // TODO: BAD + +BMPImage upscale2x_ver2(BMPImage &); // TODO: BAD + BMPImage textImg(const std::u16string &, Font *font, uint8_t scale = 1, Pixel background_color = Pixel{0, 0, 0}, Pixel font_color = Pixel{255, 255, 255}); -uint8_t ui8_clamp(int value, uint8_t min = 0, uint8_t max = 255); \ No newline at end of file +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); \ No newline at end of file diff --git a/main.cpp b/main.cpp index 8406632..d35987a 100644 --- a/main.cpp +++ b/main.cpp @@ -34,34 +34,45 @@ void lab01() { // void lab02_01() { auto img = readBMPImage("../tea.bmp"); + auto text1024 = textImg(u"1024", &font, 3); + auto text512 = textImg(u"512", &font, 3); + auto text256 = textImg(u"256", &font, 3); + auto text128 = textImg(u"128", &font, 3); auto img_512 = downscale2x(img); auto img_256 = downscale2x(img_512); auto img_128 = downscale2x(img_256); - img_512.save("../lab02/tea_512.bmp"); - img_256.save("../lab02/tea_256.bmp"); - img_128.save("../lab02/tea_128.bmp"); - auto newImg = img.appendRight(img_512).appendRight(img_256).appendRight(img_128); - newImg.save("../lab02/tea_downscale.bmp"); -// auto img_from_512 = upscale2x(img_512); + img_512.overlay(text512, 0, 0).save("../lab02/tea_512.bmp"); + img_256.overlay(text256, 0, 0).save("../lab02/tea_256.bmp"); + img_128.overlay(text128, 0, 0).save("../lab02/tea_128.bmp"); + img.overlay(text1024, 0, 0).appendRight(img_512).overlay(text512, 1024, 0).appendRight(img_256). + overlay(text256, 1536, 0).appendRight(img_128).overlay(text128, 1792, 0).save( + "../lab02/tea_downscale.bmp");; + auto img_from_512 = upscale2x(img_512).overlay(text512, 0, 0); //// auto img_from_256 = upscale2x(upscale2x(img_256)); //// auto img_from_128 = upscale2x(upscale2x(upscale2x(img_128))); -// auto tmp = upscale2x(img_256); -// auto img_from_256 = upscale2x(tmp); -// auto tmp2 = upscale2x(img_128); -// auto tmp3 = upscale2x(tmp2); -// auto img_from_128 = upscale2x(tmp3); -// img_from_512.save("../lab02/tea_from_512.bmp"); -// img_from_256.save("../lab02/tea_from_256.bmp"); -// img_from_128.save("../lab02/tea_from_128.bmp"); -// img.appendRight(img_from_512)->appendRight(img_from_256)->appendRight(img_from_128)->save("../lab02/tea_upscale.bmp"); -//// newImg2->save("../lab02/tea_upscale.bmp"); + auto tmp = upscale2x(img_256); + auto img_from_256 = upscale2x(tmp).overlay(text256, 0, 0); + auto tmp2 = upscale2x(img_128); + auto tmp3 = upscale2x(tmp2); + auto img_from_128 = upscale2x(tmp3).overlay(text128, 0, 0); + img_from_512.save("../lab02/tea_from_512.bmp"); + img_from_256.save("../lab02/tea_from_256.bmp"); + img_from_128.save("../lab02/tea_from_128.bmp"); + img.overlay(text1024, 0, 0).appendRight(img_from_512).appendRight(img_from_256).appendRight(img_from_128).save( + "../lab02/tea_upscale.bmp"); +// newImg2->save("../lab02/tea_upscale.bmp"); } // void lab02_02() { auto img = readBMPImage("../tea.bmp"); + auto ogText = textImg(u"Оригинал", &font, 3); + auto text256 = textImg(u"256 оттенков", &font, 3); + auto text128 = textImg(u"128 оттенков", &font, 3); + auto text64 = textImg(u"64 оттенка", &font, 3); + auto text32 = textImg(u"32 оттенка", &font, 3); auto gsImg = grayscale(img); - gsImg.save("../lab02/tea_grayscale_256.bmp"); + gsImg.overlay(text256, 0, 0).save("../lab02/tea_grayscale_256.bmp"); auto gsPixels = gsImg.pixels_copy(); auto width = gsImg.width(); auto height = gsImg.height(); @@ -70,39 +81,94 @@ void lab02_02() { gsPixels(i, j) = (gsPixels(i, j) / 2) * 2; } } - auto gsImg128 = BMPImage(gsPixels); + auto gsImg128 = BMPImage(gsPixels).overlay(text128, 0, 0); gsPixels = gsImg.pixels_copy(); for (int i = 0; i < height; ++i) { for (int j = 0; j < width; ++j) { gsPixels(i, j) = (gsPixels(i, j) / 4) * 4; } } - auto gsImg64 = BMPImage(gsPixels); + auto gsImg64 = BMPImage(gsPixels).overlay(text64, 0, 0); gsPixels = gsImg.pixels_copy(); for (int i = 0; i < height; ++i) { for (int j = 0; j < width; ++j) { gsPixels(i, j) = (gsPixels(i, j) / 8) * 8; } } - auto gsImg32 = BMPImage(gsPixels); + auto gsImg32 = BMPImage(gsPixels).overlay(text32, 0, 0); gsImg128.save("../lab02/tea_grayscale_128.bmp"); gsImg64.save("../lab02/tea_grayscale_64.bmp"); gsImg32.save("../lab02/tea_grayscale_32.bmp"); - gsImg.appendRight(gsImg128).appendRight(gsImg64).appendRight(gsImg32).save("../lab02/tea_grayscale.bmp"); + img.overlay(ogText, 0, 0).appendRight(gsImg).overlay(text256, 1024, 0).appendRight(gsImg128).appendRight( + gsImg64).appendRight(gsImg32).save("../lab02/tea_grayscale.bmp"); } // void lab02_03() { auto img = readBMPImage("../tea.bmp"); + auto text = textImg(u"Оригинал", &font, 3); + auto text_avrg = textImg(u"Среднее 1.5x", &font, 5); + auto text_avrg2 = textImg(u"Среднее 2x", &font, 6); + auto text_avrg3 = textImg(u"Среднее 3x", &font, 9); + auto text_lin = textImg(u"Линейное 1.5x", &font, 5); + auto text_lin2 = textImg(u"Линейное 2x", &font, 6); + auto text_lin3 = textImg(u"Линейное 3x", &font, 9); auto img_1_5 = upscale1_5x(img); + auto img_1_5_ver2 = upscale1_5x_ver2(img); auto img_2 = upscale2x(img); + auto img_2_ver2 = upscale2x_ver2(img); auto img_3 = upscale2x(img_1_5); - img_1_5.save("../lab02/lab02_03/tea_x1_5.bmp"); - img_2.save("../lab02/lab02_03/tea_x2.bmp"); - img_3.save("../lab02/lab02_03/tea_x3.bmp"); - img.appendRight(img_1_5).appendRight(img_2).appendRight(img_3).save( - "../lab02/lab02_03/tea_upscale.bmp"); //.appendRight(img_3) -// img.appendRight(img_1_5).save("../lab02/lab02_03/tea_upscale.bmp"); + auto img_3_ver2 = upscale2x_ver2(img_1_5_ver2); + img_1_5.overlay(text_avrg, 0, 0).appendRight(img_1_5_ver2).overlay(text_lin, 1536, 0).save( + "../lab02/lab02_03/tea_x1_5.bmp"); + img_2.overlay(text_avrg2, 0, 0).appendRight(img_2_ver2).overlay(text_lin2, 2048, 0).save( + "../lab02/lab02_03/tea_x2.bmp"); + img_3.overlay(text_avrg3, 0, 0).appendRight(img_3_ver2).overlay(text_lin3, 3072, 0).save( + "../lab02/lab02_03/tea_x3.bmp"); + img.overlay(text, 0, 0).appendRight(img_1_5).overlay(text_avrg, 1024, 0).appendRight(img_2) + .overlay(text_avrg2, 2560, 0).appendRight(img_3).overlay(text_avrg3, 4608, 0).save( + "../lab02/lab02_03/tea_upscale.bmp"); + img.overlay(text, 0, 0).appendRight(img_1_5_ver2).overlay(text_lin, 1024, 0).appendRight(img_2_ver2) + .overlay(text_lin, 2560, 0).appendRight(img_3_ver2).overlay(text_lin, 4608, 0).save( + "../lab02/lab02_03/tea_upscale_ver2.bmp"); +} + +void lab03() { + auto img = readBMPImage("../tea.bmp"); + 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 previtt_text = textImg(u"Фильтр Превитта", &font, 3); + auto sobel_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 previtt_image2 = filter(imgGS, previtt_mask2, 1);//.overlay(previtt_text, 0, 0); + previtt_image1.save("../lab03/previtt1.bmp"); + previtt_image2.save("../lab03/previtt2.bmp"); + PixelArray previttPixels(previtt_image1.width(), previtt_image1.height()); + for (int y = 0; y < previtt_image1.height(); ++y) { + for (int x = 0; x < previtt_image1.width(); ++x) { + previttPixels(y, x) = previtt_image1.pixels()(y, x) + previtt_image2.pixels()(y, x); + } + } + auto previtt_image = BMPImage(previttPixels).overlay(previtt_text, 0, 0); + auto sobel_image1 = filter(imgGS, sobel_mask1, 1).overlay(sobel_text, 0, 0); + auto sobel_image2 = filter(imgGS, sobel_mask2, 1).overlay(sobel_text, 0, 0); + PixelArray sobelPixels(sobel_image1.width(), sobel_image2.height()); + for (int y = 0; y < sobel_image1.height(); ++y) { + for (int x = 0; x < sobel_image1.width(); ++x) { + previttPixels(y, x) = sobel_image1.pixels()(y, x) + sobel_image2.pixels()(y, x); + } + } + auto sobel_image = BMPImage(previttPixels).overlay(sobel_text, 0, 0); + imgGS.overlay(text, 0, 0).appendRight(avrg_image).save("../lab03/avrg_filter.bmp"); + imgGS.overlay(text, 0, 0).appendRight(previtt_image).save("../lab03/previtt_filter.bmp"); + imgGS.overlay(text, 0, 0).appendRight(sobel_image).save("../lab03/sobel_filter.bmp"); } void test() { @@ -123,7 +189,7 @@ void test() { test(2, 2) = Pixel{0, 0, 0}; auto test_img = BMPImage(test); test_img.save("../test.bmp"); - auto test_scale = upscale2x(test_img); + auto test_scale = upscale1_5x_ver2(test_img); test_scale.save("../test_scale.bmp"); } @@ -162,12 +228,14 @@ void test3() { } int main() { - lab01(); + //lab01(); // lab02_01(); // lab02_02(); // lab02_03(); + lab03(); // test(); // test2(); // test3(); +// auto t = readBMPImage("../lab02/lab02_03/tea_x3.bmp"); return 0; }