#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) {
if(!result.empty()) {
return internal::rangeToBl(result, width);
}
+ std::cout << "ERROR: Empty result\n";
} while (false);
}
return internal::rangeToBl(internal::blue_noise_impl(width, height, threads), width);
}
+ std::cout << "ERROR: Invalid state (end of blue_noise fn)\n";
return {};
}
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");
fputc('\n', random_noise_image);
}
fclose(random_noise_image);
-//#endif
+#endif
//#ifndef NDEBUG
int iterations = 0;
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) {
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);
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) {
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);
fputc('\n', blue_noise_image);
}
fclose(blue_noise_image);
-//#endif
+#endif
std::cout << "Generating dither_array...\n";
std::vector<unsigned int> dither_array(count);
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;
{
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) {
fputc('\n', random_noise_image);
}
fclose(random_noise_image);
+#endif
}
if(!get_filter()) {
clReleaseCommandQueue(queue);
return {};
} else {
+#ifndef NDEBUG
internal::write_filter(filter, width, "filter_out_start.pgm");
+#endif
}
int iterations = 0;
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) {
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);
fputc('\n', blue_noise_image);
}
fclose(blue_noise_image);
+#endif
}
#ifndef NDEBUG
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
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);
}
}
}
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) {
#include <png.h>
+bool image::Base::isValid() const {
+ return getWidth() > 0 && getHeight() > 0 && getSize() > 0;
+}
+
image::Bl::Bl() :
data(),
width(0),
}
}
-int image::Bl::getSize() {
+unsigned int image::Bl::getSize() const {
return data.size();
}
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) {
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;
}
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 */,
if (png_ptr == nullptr) {
fclose(outfile);
+ std::cout << "ERROR: Failed to set up writing png file (png_ptr)\n";
return false;
}
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;
}
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) {
break;
default:
fclose(file);
+ std::cout << "ERROR: Cannot write image file, invalid type\n";
return false;
}
}
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;
-}
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;
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 {
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;
#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;
}