]> git.seodisparate.com - blue_noise_generation/commitdiff
Fix blue-noise when not using OpenCL
authorStephen Seo <seo.disparate@gmail.com>
Wed, 10 Nov 2021 10:21:33 +0000 (19:21 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 10 Nov 2021 10:21:33 +0000 (19:21 +0900)
src/blue_noise.cpp
src/blue_noise.hpp
src/image.cpp
src/image.hpp
src/main.cpp

index 5a08f04fd43fa8377d50a9bab741f97fa1bfff6c..32bc0b2e44e1e584c5126fb9509cdfb00c22f2bc 100644 (file)
@@ -7,14 +7,12 @@
 #include <memory>
 #include <string>
 #include <unordered_set>
+#include <cstdio>
 
 #include <CL/opencl.h>
 
 #include "image.hpp"
 
-#ifndef NDEBUG
-# include <cstdio>
-#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<unsigned int> dither::internal::blue_noise_impl(int width, int heigh
     std::vector<bool> 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<unsigned int> 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<unsigned int> 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<unsigned int> 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<unsigned int> 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<unsigned int> 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<unsigned int> 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<unsigned int> dither_array(count);
@@ -234,9 +240,13 @@ std::vector<unsigned int> dither::internal::blue_noise_impl(int width, int heigh
         dither_array[min] = i;
     }
     std::cout << "\nRanking last half of pixels...\n";
+    std::vector<bool> 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<unsigned int> 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<unsigned int> 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<unsigned int> 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<unsigned int> 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<unsigned int> 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<unsigned int> dither::internal::blue_noise_cl_impl(
             fputc('\n', blue_noise_image);
         }
         fclose(blue_noise_image);
+#endif
     }
 
 #ifndef NDEBUG
index dad166907b6bd4c901f185cc1a13ca34a353f13b..3a12e460437a33d2cedad6c113878d18c41d9d81 100644 (file)
@@ -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<float> &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) {
index 288a7f1c15065bb3141482fc7a34b5a44925f2da..81485a7ccbdc57973a40a3fa6cbf118147f281e5 100644 (file)
@@ -6,6 +6,10 @@
 
 #include <png.h>
 
+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;
-}
index 020abf5f441a37b4710766698486bf0eeba2996c..f976f6f18241f31dfc8a83d63a5a6ee01da55a66 100644 (file)
@@ -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<color_type> 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<color_type> getTypes() override { return { color_type::Black }; }
-        virtual int getTypeStride(color_type) override { return 0; }
+        int getTypesCount() override { return 1; }
+        std::vector<color_type> 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<uint8_t> data;
         int width;
index d973f94878a1e812a0cee3ba3e168dd13ec59bd4..1626d70c9bb0833fc89c151192158d64289027c7 100644 (file)
@@ -3,11 +3,14 @@
 #include <iostream>
 
 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;
 }