From 2357fd9c0527e616287a7f61682d4db7b1e4b98d Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Wed, 10 Nov 2021 19:21:33 +0900 Subject: [PATCH] Fix blue-noise when not using OpenCL --- src/blue_noise.cpp | 38 ++++++++++++++++++++++++++++---------- src/blue_noise.hpp | 12 ++++++++++-- src/image.cpp | 29 ++++++++++++++++++++++++----- src/image.hpp | 30 ++++++++++++++++++------------ src/main.cpp | 11 +++++++---- 5 files changed, 87 insertions(+), 33 deletions(-) diff --git a/src/blue_noise.cpp b/src/blue_noise.cpp index 5a08f04..32bc0b2 100644 --- a/src/blue_noise.cpp +++ b/src/blue_noise.cpp @@ -7,14 +7,12 @@ #include #include #include +#include #include #include "image.hpp" -#ifndef NDEBUG -# include -#endif image::Bl dither::blue_noise(int width, int height, int threads, bool use_opencl) { @@ -93,6 +91,7 @@ image::Bl dither::blue_noise(int width, int height, int threads, bool use_opencl if(!result.empty()) { return internal::rangeToBl(result, width); } + std::cout << "ERROR: Empty result\n"; } while (false); } @@ -102,6 +101,7 @@ image::Bl dither::blue_noise(int width, int height, int threads, bool use_opencl return internal::rangeToBl(internal::blue_noise_impl(width, height, threads), width); } + std::cout << "ERROR: Invalid state (end of blue_noise fn)\n"; return {}; } @@ -114,7 +114,7 @@ std::vector dither::internal::blue_noise_impl(int width, int heigh std::vector pbp = random_noise(count, count * 4 / 10); pbp.resize(count); -//#ifndef NDEBUG +#ifndef NDEBUG printf("Inserting %d pixels into image of max count %d\n", pixel_count, count); // generate image from randomized pbp FILE *random_noise_image = fopen("random_noise.pbm", "w"); @@ -126,7 +126,7 @@ std::vector dither::internal::blue_noise_impl(int width, int heigh fputc('\n', random_noise_image); } fclose(random_noise_image); -//#endif +#endif //#ifndef NDEBUG int iterations = 0; @@ -138,7 +138,9 @@ std::vector dither::internal::blue_noise_impl(int width, int heigh internal::compute_filter(pbp, width, height, count, filter_size, filter_out, precomputed.get(), threads); +#ifndef NDEBUG internal::write_filter(filter_out, width, "filter_out_start.pgm"); +#endif while(true) { //#ifndef NDEBUG // if(++iterations % 10 == 0) { @@ -149,13 +151,13 @@ std::vector dither::internal::blue_noise_impl(int width, int heigh internal::compute_filter(pbp, width, height, count, filter_size, filter_out, precomputed.get(), threads); -#ifndef NDEBUG +//#ifndef NDEBUG // for(int i = 0; i < count; ++i) { // int x, y; // std::tie(x, y) = internal::oneToTwo(i, width); // printf("%d (%d, %d): %f\n", i, x, y, filter_out[i]); // } -#endif +//#endif int min, max; std::tie(min, max) = internal::filter_minmax(filter_out, pbp); @@ -180,6 +182,7 @@ std::vector dither::internal::blue_noise_impl(int width, int heigh if(iterations % 100 == 0) { // generate blue_noise image from pbp +#ifndef NDEBUG FILE *blue_noise_image = fopen("blue_noise.pbm", "w"); fprintf(blue_noise_image, "P1\n%d %d\n", width, height); for(int y = 0; y < height; ++y) { @@ -189,13 +192,16 @@ std::vector dither::internal::blue_noise_impl(int width, int heigh fputc('\n', blue_noise_image); } fclose(blue_noise_image); +#endif } } internal::compute_filter(pbp, width, height, count, filter_size, filter_out, precomputed.get(), threads); +#ifndef NDEBUG internal::write_filter(filter_out, width, "filter_out_final.pgm"); +#endif -//#ifndef NDEBUG +#ifndef NDEBUG // generate blue_noise image from pbp FILE *blue_noise_image = fopen("blue_noise.pbm", "w"); fprintf(blue_noise_image, "P1\n%d %d\n", width, height); @@ -206,7 +212,7 @@ std::vector dither::internal::blue_noise_impl(int width, int heigh fputc('\n', blue_noise_image); } fclose(blue_noise_image); -//#endif +#endif std::cout << "Generating dither_array...\n"; std::vector dither_array(count); @@ -234,9 +240,13 @@ std::vector dither::internal::blue_noise_impl(int width, int heigh dither_array[min] = i; } std::cout << "\nRanking last half of pixels...\n"; + std::vector reversed_pbp(pbp); for (unsigned int i = (count + 1) / 2; i < (unsigned int)count; ++i) { std::cout << i << ' '; - internal::compute_filter(pbp, width, height, count, filter_size, + for(unsigned int i = 0; i < pbp.size(); ++i) { + reversed_pbp[i] = !pbp[i]; + } + internal::compute_filter(reversed_pbp, width, height, count, filter_size, filter_out, precomputed.get(), threads); std::tie(std::ignore, max) = internal::filter_minmax(filter_out, pbp); pbp[max] = true; @@ -468,6 +478,7 @@ std::vector dither::internal::blue_noise_cl_impl( { printf("Inserting %d pixels into image of max count %d\n", pixel_count, count); // generate image from randomized pbp +#ifndef NDEBUG FILE *random_noise_image = fopen("random_noise.pbm", "w"); fprintf(random_noise_image, "P1\n%d %d\n", width, height); for(int y = 0; y < height; ++y) { @@ -477,6 +488,7 @@ std::vector dither::internal::blue_noise_cl_impl( fputc('\n', random_noise_image); } fclose(random_noise_image); +#endif } if(!get_filter()) { @@ -488,7 +500,9 @@ std::vector dither::internal::blue_noise_cl_impl( clReleaseCommandQueue(queue); return {}; } else { +#ifndef NDEBUG internal::write_filter(filter, width, "filter_out_start.pgm"); +#endif } int iterations = 0; @@ -526,6 +540,7 @@ std::vector dither::internal::blue_noise_cl_impl( std::cout << "max was " << max << ", second_min is " << second_min << std::endl; // generate blue_noise image from pbp +#ifndef NDEBUG FILE *blue_noise_image = fopen("blue_noise.pbm", "w"); fprintf(blue_noise_image, "P1\n%d %d\n", width, height); for(int y = 0; y < height; ++y) { @@ -535,12 +550,14 @@ std::vector dither::internal::blue_noise_cl_impl( fputc('\n', blue_noise_image); } fclose(blue_noise_image); +#endif } } if(!get_filter()) { std::cerr << "OpenCL: Failed to execute do_filter (at end)\n"; } else { +#ifndef NDEBUG internal::write_filter(filter, width, "filter_out_final.pgm"); FILE *blue_noise_image = fopen("blue_noise.pbm", "w"); fprintf(blue_noise_image, "P1\n%d %d\n", width, height); @@ -551,6 +568,7 @@ std::vector dither::internal::blue_noise_cl_impl( fputc('\n', blue_noise_image); } fclose(blue_noise_image); +#endif } #ifndef NDEBUG diff --git a/src/blue_noise.hpp b/src/blue_noise.hpp index dad1669..3a12e46 100644 --- a/src/blue_noise.hpp +++ b/src/blue_noise.hpp @@ -90,6 +90,10 @@ namespace internal { int width, int height, int filter_size) { float sum = 0.0f; + if (filter_size % 2 == 0) { + ++filter_size; + } + // Should be range -M/2 to M/2, but size_t cannot be negative, so range // is 0 to M. // p' = (M + x - (p - M/2)) % M = (3M/2 + x - p) % M @@ -99,8 +103,8 @@ namespace internal { for(int p = 0; p < filter_size; ++p) { int p_prime = (width - filter_size / 2 + x + p) % width; if(pbp[utility::twoToOne(p_prime, q_prime, width, height)]) { - sum += gaussian((float)p - filter_size/2.0F + 0.5F, - (float)q - filter_size/2.0F + 0.5F); + sum += gaussian(p - filter_size/2, + q - filter_size/2); } } } @@ -115,6 +119,10 @@ namespace internal { const std::vector &precomputed) { float sum = 0.0f; + if (filter_size % 2 == 0) { + ++filter_size; + } + for(int q = 0; q < filter_size; ++q) { int q_prime = (height - filter_size / 2 + y + q) % height; for(int p = 0; p < filter_size; ++p) { diff --git a/src/image.cpp b/src/image.cpp index 288a7f1..81485a7 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -6,6 +6,10 @@ #include +bool image::Base::isValid() const { + return getWidth() > 0 && getHeight() > 0 && getSize() > 0; +} + image::Bl::Bl() : data(), width(0), @@ -60,7 +64,7 @@ void image::Bl::randomize() { } } -int image::Bl::getSize() { +unsigned int image::Bl::getSize() const { return data.size(); } @@ -78,8 +82,17 @@ const uint8_t* image::Bl::getDataC() const { return &data[0]; } +unsigned int image::Bl::getWidth() const { + return width; +} + +unsigned int image::Bl::getHeight() const { + return height; +} + bool image::Bl::canWriteFile(file_type type) { if(!isValid()) { + std::cout << "Cannot write image because isValid() is false\n"; return false; } switch(type) { @@ -89,18 +102,22 @@ bool image::Bl::canWriteFile(file_type type) { case file_type::PNG: return true; default: + std::cout << "Cannot write image because received invalid file_type\n"; return false; } } bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filename) { if(!isValid() || !canWriteFile(type)) { + std::cout << "ERROR: Image is not valid or cannot write file type\n"; return false; } FILE *file = fopen(filename, "r"); if(file && !canOverwrite) { fclose(file); + std::cout << "ERROR: Will not overwite existing file \"" << filename + << "\"" << std::endl; return false; } @@ -111,6 +128,7 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen if(type == file_type::PNG) { FILE *outfile = fopen(filename, "wb"); if (outfile == nullptr) { + std::cout << "ERROR: Failed to open file for writing (png)\n"; return false; } const static auto pngErrorLFn = [] (png_structp /* unused */, @@ -129,6 +147,7 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen if (png_ptr == nullptr) { fclose(outfile); + std::cout << "ERROR: Failed to set up writing png file (png_ptr)\n"; return false; } @@ -136,12 +155,14 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen if (info_ptr == nullptr) { png_destroy_write_struct(&png_ptr, nullptr); fclose(outfile); + std::cout << "ERROR: Failed to set up writing png file (png_infop)\n"; return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(outfile); + std::cout << "ERROR: Failed to write image file (png error)\n"; return false; } @@ -183,6 +204,7 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen break; default: fclose(file); + std::cout << "ERROR: Cannot write image file, invalid type\n"; return false; } for(unsigned int i = 0; i < data.size(); ++i) { @@ -205,6 +227,7 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen break; default: fclose(file); + std::cout << "ERROR: Cannot write image file, invalid type\n"; return false; } } @@ -216,7 +239,3 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen bool image::Bl::writeToFile(file_type type, bool canOverwrite, const std::string &filename) { return writeToFile(type, canOverwrite, filename.c_str()); } - -bool image::Bl::isValid() const { - return width > 0 && height > 0 && data.size() > 0; -} diff --git a/src/image.hpp b/src/image.hpp index 020abf5..f976f6f 100644 --- a/src/image.hpp +++ b/src/image.hpp @@ -34,10 +34,13 @@ namespace image { virtual void randomize() = 0; - virtual int getSize() = 0; + virtual unsigned int getSize() const = 0; virtual uint8_t* getData() = 0; virtual const uint8_t* getDataC() const = 0; + virtual unsigned int getWidth() const = 0; + virtual unsigned int getHeight() const = 0; + virtual int getTypesCount() = 0; virtual std::vector getTypes() = 0; virtual int getTypeStride(color_type type) = 0; @@ -45,6 +48,7 @@ namespace image { virtual bool canWriteFile(file_type type) = 0; virtual bool writeToFile(file_type type, bool canOverwrite, const char *filename) = 0; virtual bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) = 0; + bool isValid() const; }; class Bl : public Base { @@ -62,20 +66,22 @@ namespace image { Bl& operator=(const Bl &other) = default; Bl& operator=(Bl &&other) = default; - virtual void randomize() override; + void randomize() override; + + unsigned int getSize() const override; + uint8_t* getData() override; + const uint8_t* getDataC() const override; - virtual int getSize() override; - virtual uint8_t* getData() override; - virtual const uint8_t* getDataC() const override; + unsigned int getWidth() const override; + unsigned int getHeight() const override; - virtual int getTypesCount() override { return 1; } - virtual std::vector getTypes() override { return { color_type::Black }; } - virtual int getTypeStride(color_type) override { return 0; } + int getTypesCount() override { return 1; } + std::vector getTypes() override { return { color_type::Black }; } + int getTypeStride(color_type) override { return 0; } - virtual bool canWriteFile(file_type type) override; - virtual bool writeToFile(file_type type, bool canOverwrite, const char *filename) override; - virtual bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) override; - virtual bool isValid() const; + bool canWriteFile(file_type type) override; + bool writeToFile(file_type type, bool canOverwrite, const char *filename) override; + bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) override; private: std::vector data; int width; diff --git a/src/main.cpp b/src/main.cpp index d973f94..1626d70 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,11 +3,14 @@ #include int main(int argc, char **argv) { -//#ifndef NDEBUG std::cout << "Trying blue_noise..." << std::endl; - image::Bl bl = dither::blue_noise(64, 64, 15, true); - bl.writeToFile(image::file_type::PNG, true, "blueNoiseOut.png"); -//#endif + image::Bl bl = dither::blue_noise(32, 32, 15, false); + if(!bl.writeToFile(image::file_type::PNG, true, "blueNoiseOut.png")) { + std::cout << "ERROR: Failed to write result to file\n"; + std::cout << "size is " << bl.getSize() << ", width is " + << bl.getWidth() << ", height is " << bl.getHeight() + << std::endl; + } return 0; } -- 2.49.0