clang-format --style=google
This commit is contained in:
parent
62d15771ad
commit
ecd65fc42b
9 changed files with 1446 additions and 1480 deletions
|
@ -12,17 +12,21 @@ Args::Args()
|
||||||
output_filename_("output.png") {}
|
output_filename_("output.png") {}
|
||||||
|
|
||||||
void Args::DisplayHelp() {
|
void Args::DisplayHelp() {
|
||||||
std::cout
|
std::cout << "[-h | --help] [-b <size> | --blue-noise <size>] [--usecl | "
|
||||||
<< "[-h | --help] [-b <size> | --blue-noise <size>] [--usecl | "
|
|
||||||
"--nousecl]\n"
|
"--nousecl]\n"
|
||||||
" -h | --help\t\t\t\tDisplay this help text\n"
|
" -h | --help\t\t\t\tDisplay this help text\n"
|
||||||
" -b <size> | --blue-noise <size>\tGenerate blue noise square with "
|
" -b <size> | --blue-noise <size>\tGenerate blue noise "
|
||||||
|
"square with "
|
||||||
"size\n"
|
"size\n"
|
||||||
" --usecl | --nousecl\t\t\tUse/Disable OpenCL (enabled by default)\n"
|
" --usecl | --nousecl\t\t\tUse/Disable OpenCL (enabled by "
|
||||||
" -t <int> | --threads <int>\t\tUse CPU thread count when not using "
|
"default)\n"
|
||||||
|
" -t <int> | --threads <int>\t\tUse CPU thread count when "
|
||||||
|
"not using "
|
||||||
"OpenCL\n"
|
"OpenCL\n"
|
||||||
" -o <filelname> | --output <filename>\tOutput filename to use\n"
|
" -o <filelname> | --output <filename>\tOutput filename to "
|
||||||
" --overwrite\t\t\t\tEnable overwriting of file (default disabled)\n";
|
"use\n"
|
||||||
|
" --overwrite\t\t\t\tEnable overwriting of file (default "
|
||||||
|
"disabled)\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Args::ParseArgs(int argc, char **argv) {
|
bool Args::ParseArgs(int argc, char **argv) {
|
||||||
|
@ -53,7 +57,8 @@ bool Args::ParseArgs(int argc, char **argv) {
|
||||||
std::strcmp(argv[0], "--threads") == 0)) {
|
std::strcmp(argv[0], "--threads") == 0)) {
|
||||||
threads_ = std::strtoul(argv[1], nullptr, 10);
|
threads_ = std::strtoul(argv[1], nullptr, 10);
|
||||||
if (threads_ == 0) {
|
if (threads_ == 0) {
|
||||||
std::cout << "ERROR: Failed to parse thread count, using 4 by default"
|
std::cout << "ERROR: Failed to parse thread count, using 4 by "
|
||||||
|
"default"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
threads_ = 4;
|
threads_ = 4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,10 @@ int twoToOne(int x, int y, int width, int height) {
|
||||||
// return exp(-(x*x + y*y) / (1.5F * 1.5F * 2.0F));
|
// return exp(-(x*x + y*y) / (1.5F * 1.5F * 2.0F));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
__kernel void do_filter(
|
__kernel void do_filter(__global float *filter_out,
|
||||||
__global float *filter_out, __global const float *precomputed,
|
__global const float *precomputed,
|
||||||
__global const int *pbp, const int width, const int height,
|
__global const int *pbp, const int width,
|
||||||
const int filter_size) {
|
const int height, const int filter_size) {
|
||||||
int i = get_global_id(0);
|
int i = get_global_id(0);
|
||||||
if (i < 0 || i >= width * height) {
|
if (i < 0 || i >= width * height) {
|
||||||
return;
|
return;
|
||||||
|
@ -33,7 +33,8 @@ __kernel void do_filter(
|
||||||
int p_prime = width - filter_size / 2 + x + p;
|
int p_prime = width - filter_size / 2 + x + p;
|
||||||
if (pbp[twoToOne(p_prime, q_prime, width, height)] != 0) {
|
if (pbp[twoToOne(p_prime, q_prime, width, height)] != 0) {
|
||||||
sum += precomputed[twoToOne(p, q, filter_size, filter_size)];
|
sum += precomputed[twoToOne(p, q, filter_size, filter_size)];
|
||||||
//sum += gaussian(p - filter_size / 2.0F + 0.5F, q - filter_size / 2.0F + 0.5F);
|
// sum += gaussian(p - filter_size / 2.0F + 0.5F, q -
|
||||||
|
// filter_size / 2.0F + 0.5F);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,15 +38,13 @@ image::Bl dither::blue_noise(int width, int height, int threads,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device,
|
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, nullptr);
|
||||||
nullptr);
|
|
||||||
if (err != CL_SUCCESS) {
|
if (err != CL_SUCCESS) {
|
||||||
std::cerr << "OpenCL: Failed to get a device\n";
|
std::cerr << "OpenCL: Failed to get a device\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
context = clCreateContext(nullptr, 1, &device, nullptr, nullptr,
|
context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
|
||||||
&err);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
|
@ -59,36 +57,32 @@ image::Bl dither::blue_noise(int width, int height, int threads,
|
||||||
std::string program_string;
|
std::string program_string;
|
||||||
while (program_file.good()) {
|
while (program_file.good()) {
|
||||||
program_file.read(buf, 1024);
|
program_file.read(buf, 1024);
|
||||||
if (int read_count = program_file.gcount();
|
if (int read_count = program_file.gcount(); read_count > 0) {
|
||||||
read_count > 0) {
|
|
||||||
program_string.append(buf, read_count);
|
program_string.append(buf, read_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *string_ptr = program_string.c_str();
|
const char *string_ptr = program_string.c_str();
|
||||||
std::size_t program_size = program_string.size();
|
std::size_t program_size = program_string.size();
|
||||||
program = clCreateProgramWithSource(context, 1,
|
program = clCreateProgramWithSource(
|
||||||
(const char **)&string_ptr,
|
context, 1, (const char **)&string_ptr, &program_size, &err);
|
||||||
&program_size, &err);
|
|
||||||
if (err != CL_SUCCESS) {
|
if (err != CL_SUCCESS) {
|
||||||
std::cerr << "OpenCL: Failed to create the program\n";
|
std::cerr << "OpenCL: Failed to create the program\n";
|
||||||
clReleaseContext(context);
|
clReleaseContext(context);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = clBuildProgram(program, 1, &device, nullptr, nullptr,
|
err = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);
|
||||||
nullptr);
|
|
||||||
if (err != CL_SUCCESS) {
|
if (err != CL_SUCCESS) {
|
||||||
std::cerr << "OpenCL: Failed to build the program\n";
|
std::cerr << "OpenCL: Failed to build the program\n";
|
||||||
|
|
||||||
std::size_t log_size;
|
std::size_t log_size;
|
||||||
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,
|
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0,
|
||||||
0, nullptr, &log_size);
|
nullptr, &log_size);
|
||||||
std::unique_ptr<char[]> log =
|
std::unique_ptr<char[]> log = std::make_unique<char[]>(log_size + 1);
|
||||||
std::make_unique<char[]>(log_size + 1);
|
|
||||||
log[log_size] = 0;
|
log[log_size] = 0;
|
||||||
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,
|
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size,
|
||||||
log_size, log.get(), nullptr);
|
log.get(), nullptr);
|
||||||
std::cerr << log.get() << std::endl;
|
std::cerr << log.get() << std::endl;
|
||||||
|
|
||||||
clReleaseProgram(program);
|
clReleaseProgram(program);
|
||||||
|
@ -176,8 +170,8 @@ std::vector<unsigned int> dither::internal::blue_noise_impl(int width,
|
||||||
// }
|
// }
|
||||||
#endif
|
#endif
|
||||||
// get filter values
|
// get filter values
|
||||||
internal::compute_filter(pbp, width, height, count, filter_size,
|
internal::compute_filter(pbp, width, height, count, filter_size, filter_out,
|
||||||
filter_out, precomputed.get(), threads);
|
precomputed.get(), threads);
|
||||||
|
|
||||||
// #ifndef NDEBUG
|
// #ifndef NDEBUG
|
||||||
// for(int i = 0; i < count; ++i) {
|
// for(int i = 0; i < count; ++i) {
|
||||||
|
@ -194,8 +188,8 @@ std::vector<unsigned int> dither::internal::blue_noise_impl(int width,
|
||||||
pbp[max] = false;
|
pbp[max] = false;
|
||||||
|
|
||||||
// get filter values again
|
// get filter values again
|
||||||
internal::compute_filter(pbp, width, height, count, filter_size,
|
internal::compute_filter(pbp, width, height, count, filter_size, filter_out,
|
||||||
filter_out, precomputed.get(), threads);
|
precomputed.get(), threads);
|
||||||
|
|
||||||
// get second buffer's min
|
// get second buffer's min
|
||||||
int second_min;
|
int second_min;
|
||||||
|
@ -217,8 +211,7 @@ std::vector<unsigned int> dither::internal::blue_noise_impl(int width,
|
||||||
for (int y = 0; y < height; ++y) {
|
for (int y = 0; y < height; ++y) {
|
||||||
for (int x = 0; x < width; ++x) {
|
for (int x = 0; x < width; ++x) {
|
||||||
fprintf(blue_noise_image, "%d ",
|
fprintf(blue_noise_image, "%d ",
|
||||||
pbp[utility::twoToOne(x, y, width, height)] ? 1
|
pbp[utility::twoToOne(x, y, width, height)] ? 1 : 0);
|
||||||
: 0);
|
|
||||||
}
|
}
|
||||||
fputc('\n', blue_noise_image);
|
fputc('\n', blue_noise_image);
|
||||||
}
|
}
|
||||||
|
@ -258,21 +251,19 @@ std::vector<unsigned int> dither::internal::blue_noise_impl(int width,
|
||||||
#endif
|
#endif
|
||||||
internal::compute_filter(pbp, width, height, count, filter_size,
|
internal::compute_filter(pbp, width, height, count, filter_size,
|
||||||
filter_out, precomputed.get(), threads);
|
filter_out, precomputed.get(), threads);
|
||||||
std::tie(std::ignore, max) =
|
std::tie(std::ignore, max) = internal::filter_minmax(filter_out, pbp);
|
||||||
internal::filter_minmax(filter_out, pbp);
|
|
||||||
pbp[max] = false;
|
pbp[max] = false;
|
||||||
dither_array[max] = i;
|
dither_array[max] = i;
|
||||||
}
|
}
|
||||||
pbp = pbp_copy;
|
pbp = pbp_copy;
|
||||||
}
|
}
|
||||||
std::cout << "\nRanking remainder of first half of pixels...\n";
|
std::cout << "\nRanking remainder of first half of pixels...\n";
|
||||||
for (unsigned int i = pixel_count; i < (unsigned int)((count + 1) / 2);
|
for (unsigned int i = pixel_count; i < (unsigned int)((count + 1) / 2); ++i) {
|
||||||
++i) {
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout << i << ' ';
|
std::cout << i << ' ';
|
||||||
#endif
|
#endif
|
||||||
internal::compute_filter(pbp, width, height, count, filter_size,
|
internal::compute_filter(pbp, width, height, count, filter_size, filter_out,
|
||||||
filter_out, precomputed.get(), threads);
|
precomputed.get(), threads);
|
||||||
std::tie(min, std::ignore) = internal::filter_minmax(filter_out, pbp);
|
std::tie(min, std::ignore) = internal::filter_minmax(filter_out, pbp);
|
||||||
pbp[min] = true;
|
pbp[min] = true;
|
||||||
dither_array[min] = i;
|
dither_array[min] = i;
|
||||||
|
@ -286,9 +277,8 @@ std::vector<unsigned int> dither::internal::blue_noise_impl(int width,
|
||||||
for (unsigned int i = 0; i < pbp.size(); ++i) {
|
for (unsigned int i = 0; i < pbp.size(); ++i) {
|
||||||
reversed_pbp[i] = !pbp[i];
|
reversed_pbp[i] = !pbp[i];
|
||||||
}
|
}
|
||||||
internal::compute_filter(reversed_pbp, width, height, count,
|
internal::compute_filter(reversed_pbp, width, height, count, filter_size,
|
||||||
filter_size, filter_out, precomputed.get(),
|
filter_out, precomputed.get(), threads);
|
||||||
threads);
|
|
||||||
std::tie(std::ignore, max) = internal::filter_minmax(filter_out, pbp);
|
std::tie(std::ignore, max) = internal::filter_minmax(filter_out, pbp);
|
||||||
pbp[max] = true;
|
pbp[max] = true;
|
||||||
dither_array[max] = i;
|
dither_array[max] = i;
|
||||||
|
@ -318,9 +308,9 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
|
|
||||||
d_filter_out = clCreateBuffer(context, CL_MEM_WRITE_ONLY,
|
d_filter_out = clCreateBuffer(context, CL_MEM_WRITE_ONLY,
|
||||||
count * sizeof(float), nullptr, nullptr);
|
count * sizeof(float), nullptr, nullptr);
|
||||||
d_precomputed = clCreateBuffer(context, CL_MEM_READ_ONLY,
|
d_precomputed =
|
||||||
precomputed.size() * sizeof(float), nullptr,
|
clCreateBuffer(context, CL_MEM_READ_ONLY,
|
||||||
nullptr);
|
precomputed.size() * sizeof(float), nullptr, nullptr);
|
||||||
d_pbp = clCreateBuffer(context, CL_MEM_READ_ONLY, count * sizeof(int),
|
d_pbp = clCreateBuffer(context, CL_MEM_READ_ONLY, count * sizeof(int),
|
||||||
nullptr, nullptr);
|
nullptr, nullptr);
|
||||||
|
|
||||||
|
@ -372,8 +362,7 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clSetKernelArg(kernel, 0, sizeof(cl_mem), &d_filter_out) !=
|
if (clSetKernelArg(kernel, 0, sizeof(cl_mem), &d_filter_out) != CL_SUCCESS) {
|
||||||
CL_SUCCESS) {
|
|
||||||
std::cerr << "OpenCL: Failed to set kernel arg 0\n";
|
std::cerr << "OpenCL: Failed to set kernel arg 0\n";
|
||||||
clReleaseKernel(kernel);
|
clReleaseKernel(kernel);
|
||||||
clReleaseMemObject(d_pbp);
|
clReleaseMemObject(d_pbp);
|
||||||
|
@ -382,8 +371,7 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
clReleaseCommandQueue(queue);
|
clReleaseCommandQueue(queue);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (clSetKernelArg(kernel, 1, sizeof(cl_mem), &d_precomputed) !=
|
if (clSetKernelArg(kernel, 1, sizeof(cl_mem), &d_precomputed) != CL_SUCCESS) {
|
||||||
CL_SUCCESS) {
|
|
||||||
std::cerr << "OpenCL: Failed to set kernel arg 1\n";
|
std::cerr << "OpenCL: Failed to set kernel arg 1\n";
|
||||||
clReleaseKernel(kernel);
|
clReleaseKernel(kernel);
|
||||||
clReleaseMemObject(d_pbp);
|
clReleaseMemObject(d_pbp);
|
||||||
|
@ -432,8 +420,7 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (clSetKernelArg(kernel, 5, sizeof(int), &filter_size) !=
|
if (clSetKernelArg(kernel, 5, sizeof(int), &filter_size) != CL_SUCCESS) {
|
||||||
CL_SUCCESS) {
|
|
||||||
std::cerr << "OpenCL: Failed to set kernel arg 4\n";
|
std::cerr << "OpenCL: Failed to set kernel arg 4\n";
|
||||||
clReleaseKernel(kernel);
|
clReleaseKernel(kernel);
|
||||||
clReleaseMemObject(d_pbp);
|
clReleaseMemObject(d_pbp);
|
||||||
|
@ -455,19 +442,18 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
clReleaseCommandQueue(queue);
|
clReleaseCommandQueue(queue);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
global_size =
|
global_size = (std::size_t)std::ceil(count / (float)local_size) * local_size;
|
||||||
(std::size_t)std::ceil(count / (float)local_size) * local_size;
|
|
||||||
|
|
||||||
std::cout << "OpenCL: global = " << global_size
|
std::cout << "OpenCL: global = " << global_size << ", local = " << local_size
|
||||||
<< ", local = " << local_size << std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
std::vector<float> filter(count);
|
std::vector<float> filter(count);
|
||||||
|
|
||||||
bool reversed_pbp = false;
|
bool reversed_pbp = false;
|
||||||
|
|
||||||
const auto get_filter = [&queue, &kernel, &global_size, &local_size,
|
const auto get_filter = [&queue, &kernel, &global_size, &local_size,
|
||||||
&d_filter_out, &d_pbp, &pbp, &pbp_i, &count,
|
&d_filter_out, &d_pbp, &pbp, &pbp_i, &count, &filter,
|
||||||
&filter, &err, &reversed_pbp]() -> bool {
|
&err, &reversed_pbp]() -> bool {
|
||||||
for (unsigned int i = 0; i < pbp.size(); ++i) {
|
for (unsigned int i = 0; i < pbp.size(); ++i) {
|
||||||
if (reversed_pbp) {
|
if (reversed_pbp) {
|
||||||
pbp_i[i] = pbp[i] ? 0 : 1;
|
pbp_i[i] = pbp[i] ? 0 : 1;
|
||||||
|
@ -476,15 +462,13 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (clEnqueueWriteBuffer(queue, d_pbp, CL_TRUE, 0, count * sizeof(int),
|
if (clEnqueueWriteBuffer(queue, d_pbp, CL_TRUE, 0, count * sizeof(int),
|
||||||
&pbp_i[0], 0, nullptr,
|
&pbp_i[0], 0, nullptr, nullptr) != CL_SUCCESS) {
|
||||||
nullptr) != CL_SUCCESS) {
|
|
||||||
std::cerr << "OpenCL: Failed to write to d_pbp buffer\n";
|
std::cerr << "OpenCL: Failed to write to d_pbp buffer\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err = clEnqueueNDRangeKernel(queue, kernel, 1, nullptr,
|
if (err = clEnqueueNDRangeKernel(queue, kernel, 1, nullptr, &global_size,
|
||||||
&global_size, &local_size, 0, nullptr,
|
&local_size, 0, nullptr, nullptr);
|
||||||
nullptr);
|
|
||||||
err != CL_SUCCESS) {
|
err != CL_SUCCESS) {
|
||||||
std::cerr << "OpenCL: Failed to enqueue task: ";
|
std::cerr << "OpenCL: Failed to enqueue task: ";
|
||||||
switch (err) {
|
switch (err) {
|
||||||
|
@ -530,9 +514,8 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
|
|
||||||
clFinish(queue);
|
clFinish(queue);
|
||||||
|
|
||||||
clEnqueueReadBuffer(queue, d_filter_out, CL_TRUE, 0,
|
clEnqueueReadBuffer(queue, d_filter_out, CL_TRUE, 0, count * sizeof(float),
|
||||||
count * sizeof(float), &filter[0], 0, nullptr,
|
&filter[0], 0, nullptr, nullptr);
|
||||||
nullptr);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -594,8 +577,7 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
|
|
||||||
// get second buffer's min
|
// get second buffer's min
|
||||||
int second_min;
|
int second_min;
|
||||||
std::tie(second_min, std::ignore) =
|
std::tie(second_min, std::ignore) = internal::filter_minmax(filter, pbp);
|
||||||
internal::filter_minmax(filter, pbp);
|
|
||||||
|
|
||||||
if (second_min == max) {
|
if (second_min == max) {
|
||||||
pbp[max] = true;
|
pbp[max] = true;
|
||||||
|
@ -614,8 +596,7 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
for (int y = 0; y < height; ++y) {
|
for (int y = 0; y < height; ++y) {
|
||||||
for (int x = 0; x < width; ++x) {
|
for (int x = 0; x < width; ++x) {
|
||||||
fprintf(blue_noise_image, "%d ",
|
fprintf(blue_noise_image, "%d ",
|
||||||
pbp[utility::twoToOne(x, y, width, height)] ? 1
|
pbp[utility::twoToOne(x, y, width, height)] ? 1 : 0);
|
||||||
: 0);
|
|
||||||
}
|
}
|
||||||
fputc('\n', blue_noise_image);
|
fputc('\n', blue_noise_image);
|
||||||
}
|
}
|
||||||
|
@ -645,8 +626,7 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
{
|
{
|
||||||
image::Bl pbp_image = toBl(pbp, width);
|
image::Bl pbp_image = toBl(pbp, width);
|
||||||
pbp_image.writeToFile(image::file_type::PNG, true,
|
pbp_image.writeToFile(image::file_type::PNG, true, "debug_pbp_before.png");
|
||||||
"debug_pbp_before.png");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -678,13 +658,11 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
pbp = pbp_copy;
|
pbp = pbp_copy;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
image::Bl min_pixels = internal::rangeToBl(dither_array, width);
|
image::Bl min_pixels = internal::rangeToBl(dither_array, width);
|
||||||
min_pixels.writeToFile(image::file_type::PNG, true,
|
min_pixels.writeToFile(image::file_type::PNG, true, "da_min_pixels.png");
|
||||||
"da_min_pixels.png");
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
std::cout << "\nRanking remainder of first half of pixels...\n";
|
std::cout << "\nRanking remainder of first half of pixels...\n";
|
||||||
for (unsigned int i = pixel_count; i < (unsigned int)((count + 1) / 2);
|
for (unsigned int i = pixel_count; i < (unsigned int)((count + 1) / 2); ++i) {
|
||||||
++i) {
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout << i << ' ';
|
std::cout << i << ' ';
|
||||||
#endif
|
#endif
|
||||||
|
@ -703,8 +681,7 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
{
|
{
|
||||||
image::Bl min_pixels = internal::rangeToBl(dither_array, width);
|
image::Bl min_pixels = internal::rangeToBl(dither_array, width);
|
||||||
min_pixels.writeToFile(image::file_type::PNG, true,
|
min_pixels.writeToFile(image::file_type::PNG, true, "da_mid_pixels.png");
|
||||||
"da_mid_pixels.png");
|
|
||||||
get_filter();
|
get_filter();
|
||||||
internal::write_filter(filter, width, "filter_mid.pgm");
|
internal::write_filter(filter, width, "filter_mid.pgm");
|
||||||
image::Bl pbp_image = toBl(pbp, width);
|
image::Bl pbp_image = toBl(pbp, width);
|
||||||
|
@ -736,8 +713,7 @@ std::vector<unsigned int> dither::internal::blue_noise_cl_impl(
|
||||||
get_filter();
|
get_filter();
|
||||||
internal::write_filter(filter, width, "filter_after.pgm");
|
internal::write_filter(filter, width, "filter_after.pgm");
|
||||||
image::Bl pbp_image = toBl(pbp, width);
|
image::Bl pbp_image = toBl(pbp, width);
|
||||||
pbp_image.writeToFile(image::file_type::PNG, true,
|
pbp_image.writeToFile(image::file_type::PNG, true, "debug_pbp_after.png");
|
||||||
"debug_pbp_after.png");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,41 @@
|
||||||
#ifndef BLUE_NOISE_HPP
|
#ifndef BLUE_NOISE_HPP
|
||||||
#define BLUE_NOISE_HPP
|
#define BLUE_NOISE_HPP
|
||||||
|
|
||||||
#include <limits>
|
#include <CL/opencl.h>
|
||||||
#include <vector>
|
|
||||||
#include <functional>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
#include <chrono>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <queue>
|
|
||||||
#include <random>
|
|
||||||
#include <cassert>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <iostream>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include <sys/sysinfo.h>
|
#include <sys/sysinfo.h>
|
||||||
|
|
||||||
#include <CL/opencl.h>
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cmath>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <limits>
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
#include <random>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <thread>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "utility.hpp"
|
|
||||||
#include "image.hpp"
|
#include "image.hpp"
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
namespace dither {
|
namespace dither {
|
||||||
|
|
||||||
image::Bl blue_noise(int width, int height, int threads = 1, bool use_opencl = true);
|
image::Bl blue_noise(int width, int height, int threads = 1,
|
||||||
|
bool use_opencl = true);
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
std::vector<unsigned int> blue_noise_impl(int width, int height, int threads = 1);
|
std::vector<unsigned int> blue_noise_impl(int width, int height,
|
||||||
std::vector<unsigned int> blue_noise_cl_impl(
|
int threads = 1);
|
||||||
const int width, const int height, const int filter_size,
|
std::vector<unsigned int> blue_noise_cl_impl(const int width, const int height,
|
||||||
cl_context context, cl_device_id device, cl_program program);
|
const int filter_size,
|
||||||
|
cl_context context,
|
||||||
|
cl_device_id device,
|
||||||
|
cl_program program);
|
||||||
|
|
||||||
inline std::vector<bool> random_noise(int size, int subsize) {
|
inline std::vector<bool> random_noise(int size, int subsize) {
|
||||||
std::vector<bool> pbp(size);
|
std::vector<bool> pbp(size);
|
||||||
|
@ -77,18 +80,15 @@ namespace internal {
|
||||||
|
|
||||||
for (int i = 0; i < size * size; ++i) {
|
for (int i = 0; i < size * size; ++i) {
|
||||||
auto xy = utility::oneToTwo(i, size);
|
auto xy = utility::oneToTwo(i, size);
|
||||||
precomputed.push_back(gaussian(
|
precomputed.push_back(
|
||||||
xy.first - (size / 2),
|
gaussian(xy.first - (size / 2), xy.second - (size / 2)));
|
||||||
xy.second - (size / 2)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return precomputed;
|
return precomputed;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float filter(
|
inline float filter(const std::vector<bool> &pbp, int x, int y, int width,
|
||||||
const std::vector<bool>& pbp,
|
int height, int filter_size) {
|
||||||
int x, int y,
|
|
||||||
int width, int height, int filter_size) {
|
|
||||||
float sum = 0.0f;
|
float sum = 0.0f;
|
||||||
|
|
||||||
if (filter_size % 2 == 0) {
|
if (filter_size % 2 == 0) {
|
||||||
|
@ -104,8 +104,7 @@ namespace internal {
|
||||||
for (int p = 0; p < filter_size; ++p) {
|
for (int p = 0; p < filter_size; ++p) {
|
||||||
int p_prime = (width - filter_size / 2 + x + p) % width;
|
int p_prime = (width - filter_size / 2 + x + p) % width;
|
||||||
if (pbp[utility::twoToOne(p_prime, q_prime, width, height)]) {
|
if (pbp[utility::twoToOne(p_prime, q_prime, width, height)]) {
|
||||||
sum += gaussian(p - filter_size/2,
|
sum += gaussian(p - filter_size / 2, q - filter_size / 2);
|
||||||
q - filter_size/2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,9 +112,7 @@ namespace internal {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float filter_with_precomputed(
|
inline float filter_with_precomputed(const std::vector<bool> &pbp, int x, int y,
|
||||||
const std::vector<bool>& pbp,
|
|
||||||
int x, int y,
|
|
||||||
int width, int height, int filter_size,
|
int width, int height, int filter_size,
|
||||||
const std::vector<float> &precomputed) {
|
const std::vector<float> &precomputed) {
|
||||||
float sum = 0.0f;
|
float sum = 0.0f;
|
||||||
|
@ -137,9 +134,9 @@ namespace internal {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void compute_filter(
|
inline void compute_filter(const std::vector<bool> &pbp, int width, int height,
|
||||||
const std::vector<bool> &pbp, int width, int height,
|
int count, int filter_size,
|
||||||
int count, int filter_size, std::vector<float> &filter_out,
|
std::vector<float> &filter_out,
|
||||||
const std::vector<float> *precomputed = nullptr,
|
const std::vector<float> *precomputed = nullptr,
|
||||||
int threads = 1) {
|
int threads = 1) {
|
||||||
if (threads == 1) {
|
if (threads == 1) {
|
||||||
|
@ -147,8 +144,8 @@ namespace internal {
|
||||||
for (int y = 0; y < height; ++y) {
|
for (int y = 0; y < height; ++y) {
|
||||||
for (int x = 0; x < width; ++x) {
|
for (int x = 0; x < width; ++x) {
|
||||||
filter_out[utility::twoToOne(x, y, width, height)] =
|
filter_out[utility::twoToOne(x, y, width, height)] =
|
||||||
internal::filter_with_precomputed(
|
internal::filter_with_precomputed(pbp, x, y, width, height,
|
||||||
pbp, x, y, width, height, filter_size, *precomputed);
|
filter_size, *precomputed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -172,11 +169,10 @@ namespace internal {
|
||||||
std::unique_lock lock(cv_mutex);
|
std::unique_lock lock(cv_mutex);
|
||||||
active_count += 1;
|
active_count += 1;
|
||||||
}
|
}
|
||||||
std::thread t([] (int *ac, std::mutex *cvm,
|
std::thread t(
|
||||||
std::condition_variable *cv, int i,
|
[](int *ac, std::mutex *cvm, std::condition_variable *cv, int i,
|
||||||
const std::vector<bool> *pbp, int width,
|
const std::vector<bool> *pbp, int width, int height,
|
||||||
int height, int filter_size,
|
int filter_size, std::vector<float> *fout,
|
||||||
std::vector<float> *fout,
|
|
||||||
const std::vector<float> *precomputed) {
|
const std::vector<float> *precomputed) {
|
||||||
int x, y;
|
int x, y;
|
||||||
std::tie(x, y) = utility::oneToTwo(i, width);
|
std::tie(x, y) = utility::oneToTwo(i, width);
|
||||||
|
@ -186,8 +182,8 @@ namespace internal {
|
||||||
*ac -= 1;
|
*ac -= 1;
|
||||||
cv->notify_all();
|
cv->notify_all();
|
||||||
},
|
},
|
||||||
&active_count, &cv_mutex, &cv, i, &pbp, width, height,
|
&active_count, &cv_mutex, &cv, i, &pbp, width, height, filter_size,
|
||||||
filter_size, &filter_out, precomputed);
|
&filter_out, precomputed);
|
||||||
t.detach();
|
t.detach();
|
||||||
|
|
||||||
std::unique_lock lock(cv_mutex);
|
std::unique_lock lock(cv_mutex);
|
||||||
|
@ -201,21 +197,20 @@ namespace internal {
|
||||||
std::unique_lock lock(cv_mutex);
|
std::unique_lock lock(cv_mutex);
|
||||||
active_count += 1;
|
active_count += 1;
|
||||||
}
|
}
|
||||||
std::thread t([] (int *ac, std::mutex *cvm,
|
std::thread t(
|
||||||
std::condition_variable *cv, int i,
|
[](int *ac, std::mutex *cvm, std::condition_variable *cv, int i,
|
||||||
const std::vector<bool> *pbp, int width,
|
const std::vector<bool> *pbp, int width, int height,
|
||||||
int height, int filter_size,
|
int filter_size, std::vector<float> *fout) {
|
||||||
std::vector<float> *fout) {
|
|
||||||
int x, y;
|
int x, y;
|
||||||
std::tie(x, y) = utility::oneToTwo(i, width);
|
std::tie(x, y) = utility::oneToTwo(i, width);
|
||||||
(*fout)[i] = internal::filter(
|
(*fout)[i] =
|
||||||
*pbp, x, y, width, height, filter_size);
|
internal::filter(*pbp, x, y, width, height, filter_size);
|
||||||
std::unique_lock lock(*cvm);
|
std::unique_lock lock(*cvm);
|
||||||
*ac -= 1;
|
*ac -= 1;
|
||||||
cv->notify_all();
|
cv->notify_all();
|
||||||
},
|
},
|
||||||
&active_count, &cv_mutex, &cv, i, &pbp, width, height,
|
&active_count, &cv_mutex, &cv, i, &pbp, width, height, filter_size,
|
||||||
filter_size, &filter_out);
|
&filter_out);
|
||||||
t.detach();
|
t.detach();
|
||||||
|
|
||||||
std::unique_lock lock(cv_mutex);
|
std::unique_lock lock(cv_mutex);
|
||||||
|
@ -229,7 +224,6 @@ namespace internal {
|
||||||
cv.wait_for(lock, std::chrono::seconds(1));
|
cv.wait_for(lock, std::chrono::seconds(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::pair<int, int> filter_minmax(const std::vector<float> &filter,
|
inline std::pair<int, int> filter_minmax(const std::vector<float> &filter,
|
||||||
|
@ -267,15 +261,15 @@ namespace internal {
|
||||||
return {min_index, max_index};
|
return {min_index, max_index};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::pair<int, int> filter_abs_minmax(
|
inline std::pair<int, int> filter_abs_minmax(const std::vector<float> &filter) {
|
||||||
const std::vector<float> &filter) {
|
|
||||||
float min = std::numeric_limits<float>::infinity();
|
float min = std::numeric_limits<float>::infinity();
|
||||||
float max = -std::numeric_limits<float>::infinity();
|
float max = -std::numeric_limits<float>::infinity();
|
||||||
int min_index = -1;
|
int min_index = -1;
|
||||||
int max_index = -1;
|
int max_index = -1;
|
||||||
|
|
||||||
std::default_random_engine re(std::random_device{}());
|
std::default_random_engine re(std::random_device{}());
|
||||||
std::size_t startIdx = std::uniform_int_distribution<std::size_t>(0, filter.size() - 1)(re);
|
std::size_t startIdx =
|
||||||
|
std::uniform_int_distribution<std::size_t>(0, filter.size() - 1)(re);
|
||||||
|
|
||||||
for (std::vector<float>::size_type i = startIdx; i < filter.size(); ++i) {
|
for (std::vector<float>::size_type i = startIdx; i < filter.size(); ++i) {
|
||||||
if (filter[i] < min) {
|
if (filter[i] < min) {
|
||||||
|
@ -301,9 +295,8 @@ namespace internal {
|
||||||
return {min_index, max_index};
|
return {min_index, max_index};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int get_one_or_zero(
|
inline int get_one_or_zero(const std::vector<bool> &pbp, bool get_one, int idx,
|
||||||
const std::vector<bool>& pbp, bool get_one,
|
int width, int height) {
|
||||||
int idx, int width, int height) {
|
|
||||||
std::queue<int> checking_indices;
|
std::queue<int> checking_indices;
|
||||||
|
|
||||||
auto xy = utility::oneToTwo(idx, width);
|
auto xy = utility::oneToTwo(idx, width);
|
||||||
|
@ -365,18 +358,19 @@ namespace internal {
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void write_filter(const std::vector<float> &filter, int width, const char *filename) {
|
inline void write_filter(const std::vector<float> &filter, int width,
|
||||||
|
const char *filename) {
|
||||||
int min, max;
|
int min, max;
|
||||||
std::tie(min, max) = filter_abs_minmax(filter);
|
std::tie(min, max) = filter_abs_minmax(filter);
|
||||||
|
|
||||||
printf("Writing to %s, min is %.3f, max is %.3f\n", filename, filter[min], filter[max]);
|
printf("Writing to %s, min is %.3f, max is %.3f\n", filename, filter[min],
|
||||||
|
filter[max]);
|
||||||
FILE *filter_image = fopen(filename, "w");
|
FILE *filter_image = fopen(filename, "w");
|
||||||
fprintf(filter_image, "P2\n%d %d\n255\n", width, (int)filter.size() / width);
|
fprintf(filter_image, "P2\n%d %d\n255\n", width, (int)filter.size() / width);
|
||||||
for (std::vector<float>::size_type i = 0; i < filter.size(); ++i) {
|
for (std::vector<float>::size_type i = 0; i < filter.size(); ++i) {
|
||||||
fprintf(filter_image, "%d ",
|
fprintf(filter_image, "%d ",
|
||||||
(int)(((filter[i] - filter[min])
|
(int)(((filter[i] - filter[min]) / (filter[max] - filter[min])) *
|
||||||
/ (filter[max] - filter[min]))
|
255.0f));
|
||||||
* 255.0f));
|
|
||||||
if ((i + 1) % width == 0) {
|
if ((i + 1) % width == 0) {
|
||||||
fputc('\n', filter_image);
|
fputc('\n', filter_image);
|
||||||
}
|
}
|
||||||
|
@ -386,8 +380,9 @@ namespace internal {
|
||||||
|
|
||||||
inline image::Bl toBl(const std::vector<bool> &pbp, int width) {
|
inline image::Bl toBl(const std::vector<bool> &pbp, int width) {
|
||||||
image::Bl bwImage(width, pbp.size() / width);
|
image::Bl bwImage(width, pbp.size() / width);
|
||||||
assert((unsigned long)bwImage.getSize() >= pbp.size()
|
assert((unsigned long)bwImage.getSize() >= pbp.size() &&
|
||||||
&& "New image::Bl size too small (pbp's size is not a multiple of width)");
|
"New image::Bl size too small (pbp's size is not a multiple of "
|
||||||
|
"width)");
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pbp.size(); ++i) {
|
for (unsigned int i = 0; i < pbp.size(); ++i) {
|
||||||
bwImage.getData()[i] = pbp[i] ? 255 : 0;
|
bwImage.getData()[i] = pbp[i] ? 255 : 0;
|
||||||
|
@ -410,25 +405,27 @@ namespace internal {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout << "rangeToBl: Got min == " << min << " and max == " << max << std::endl;
|
std::cout << "rangeToBl: Got min == " << min << " and max == " << max
|
||||||
|
<< std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
max -= min;
|
max -= min;
|
||||||
|
|
||||||
image::Bl grImage(width, values.size() / width);
|
image::Bl grImage(width, values.size() / width);
|
||||||
assert((unsigned long)grImage.getSize() >= values.size()
|
assert((unsigned long)grImage.getSize() >= values.size() &&
|
||||||
&& "New image::Bl size too small (values' size is not a multiple of width)");
|
"New image::Bl size too small (values' size is not a multiple of "
|
||||||
|
"width)");
|
||||||
|
|
||||||
for (unsigned int i = 0; i < values.size(); ++i) {
|
for (unsigned int i = 0; i < values.size(); ++i) {
|
||||||
grImage.getData()[i] = std::round(((float)((int)(values[i]) - min) / (float)max) * 255.0F);
|
grImage.getData()[i] =
|
||||||
|
std::round(((float)((int)(values[i]) - min) / (float)max) * 255.0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
return grImage;
|
return grImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::pair<int, int> filter_minmax_in_range(int start, int width,
|
inline std::pair<int, int> filter_minmax_in_range(
|
||||||
int height,
|
int start, int width, int height, int range,
|
||||||
int range,
|
|
||||||
const std::vector<float> &vec) {
|
const std::vector<float> &vec) {
|
||||||
float max = -std::numeric_limits<float>::infinity();
|
float max = -std::numeric_limits<float>::infinity();
|
||||||
float min = std::numeric_limits<float>::infinity();
|
float min = std::numeric_limits<float>::infinity();
|
||||||
|
@ -437,8 +434,10 @@ namespace internal {
|
||||||
int minIdx = -1;
|
int minIdx = -1;
|
||||||
|
|
||||||
auto startXY = utility::oneToTwo(start, width);
|
auto startXY = utility::oneToTwo(start, width);
|
||||||
for(int y = startXY.second - range / 2; y <= startXY.second + range / 2; ++y) {
|
for (int y = startXY.second - range / 2; y <= startXY.second + range / 2;
|
||||||
for(int x = startXY.first - range / 2; x <= startXY.first + range / 2; ++x) {
|
++y) {
|
||||||
|
for (int x = startXY.first - range / 2; x <= startXY.first + range / 2;
|
||||||
|
++x) {
|
||||||
int idx = utility::twoToOne(x, y, width, height);
|
int idx = utility::twoToOne(x, y, width, height);
|
||||||
if (idx == start) {
|
if (idx == start) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -463,7 +462,7 @@ namespace internal {
|
||||||
}
|
}
|
||||||
return {minIdx, maxIdx};
|
return {minIdx, maxIdx};
|
||||||
}
|
}
|
||||||
} // namespace dither::internal
|
} // namespace internal
|
||||||
|
|
||||||
} // namespace dither
|
} // namespace dither
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,28 @@
|
||||||
#include "image.hpp"
|
#include "image.hpp"
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <random>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <png.h>
|
#include <png.h>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
bool image::Base::isValid() const {
|
bool image::Base::isValid() const {
|
||||||
return getWidth() > 0 && getHeight() > 0 && getSize() > 0;
|
return getWidth() > 0 && getHeight() > 0 && getSize() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
image::Bl::Bl() :
|
image::Bl::Bl() : data(), width(0), height(0) {}
|
||||||
data(),
|
|
||||||
width(0),
|
|
||||||
height(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
image::Bl::Bl(int width, int height) :
|
image::Bl::Bl(int width, int height)
|
||||||
data(width * height),
|
: data(width * height), width(width), height(height) {}
|
||||||
width(width),
|
|
||||||
height(height)
|
|
||||||
{}
|
|
||||||
|
|
||||||
image::Bl::Bl(const std::vector<uint8_t> &data, int width) :
|
image::Bl::Bl(const std::vector<uint8_t> &data, int width)
|
||||||
data(data),
|
: data(data), width(width), height(data.size() / width) {}
|
||||||
width(width),
|
|
||||||
height(data.size() / width)
|
|
||||||
{}
|
|
||||||
|
|
||||||
image::Bl::Bl(std::vector<uint8_t> &&data, int width) :
|
image::Bl::Bl(std::vector<uint8_t> &&data, int width)
|
||||||
data(std::move(data)),
|
: data(std::move(data)), width(width), height(data.size() / width) {}
|
||||||
width(width),
|
|
||||||
height(data.size() / width)
|
|
||||||
{}
|
|
||||||
|
|
||||||
image::Bl::Bl(const std::vector<float> &data, int width) :
|
image::Bl::Bl(const std::vector<float> &data, int width)
|
||||||
data{},
|
: data{}, width(width), height(data.size() / width) {
|
||||||
width(width),
|
|
||||||
height(data.size() / width)
|
|
||||||
{
|
|
||||||
for (float gspixel : data) {
|
for (float gspixel : data) {
|
||||||
this->data.push_back(static_cast<uint8_t>(255.0F * gspixel));
|
this->data.push_back(static_cast<uint8_t>(255.0F * gspixel));
|
||||||
}
|
}
|
||||||
|
@ -57,16 +41,15 @@ void image::Bl::randomize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < data.size() - 1; ++i) {
|
for (unsigned int i = 0; i < data.size() - 1; ++i) {
|
||||||
int ridx = dist(re, decltype(dist)::param_type{i+1, (unsigned int)data.size()-1});
|
int ridx = dist(
|
||||||
|
re, decltype(dist)::param_type{i + 1, (unsigned int)data.size() - 1});
|
||||||
uint8_t temp = data[i];
|
uint8_t temp = data[i];
|
||||||
data[i] = data[ridx];
|
data[i] = data[ridx];
|
||||||
data[ridx] = temp;
|
data[ridx] = temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int image::Bl::getSize() const {
|
unsigned int image::Bl::getSize() const { return data.size(); }
|
||||||
return data.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *image::Bl::getData() {
|
uint8_t *image::Bl::getData() {
|
||||||
if (!isValid()) {
|
if (!isValid()) {
|
||||||
|
@ -82,13 +65,9 @@ const uint8_t* image::Bl::getDataC() const {
|
||||||
return &data[0];
|
return &data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int image::Bl::getWidth() const {
|
unsigned int image::Bl::getWidth() const { return width; }
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int image::Bl::getHeight() const {
|
unsigned int image::Bl::getHeight() const { return height; }
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool image::Bl::canWriteFile(file_type type) {
|
bool image::Bl::canWriteFile(file_type type) {
|
||||||
if (!isValid()) {
|
if (!isValid()) {
|
||||||
|
@ -102,12 +81,14 @@ bool image::Bl::canWriteFile(file_type type) {
|
||||||
case file_type::PNG:
|
case file_type::PNG:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
std::cout << "Cannot write image because received invalid file_type\n";
|
std::cout << "Cannot write image because received invalid "
|
||||||
|
"file_type\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filename) {
|
bool image::Bl::writeToFile(file_type type, bool canOverwrite,
|
||||||
|
const char *filename) {
|
||||||
if (!isValid() || !canWriteFile(type)) {
|
if (!isValid() || !canWriteFile(type)) {
|
||||||
std::cout << "ERROR: Image is not valid or cannot write file type\n";
|
std::cout << "ERROR: Image is not valid or cannot write file type\n";
|
||||||
return false;
|
return false;
|
||||||
|
@ -116,8 +97,8 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen
|
||||||
FILE *file = fopen(filename, "r");
|
FILE *file = fopen(filename, "r");
|
||||||
if (file && !canOverwrite) {
|
if (file && !canOverwrite) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
std::cout << "ERROR: Will not overwite existing file \"" << filename
|
std::cout << "ERROR: Will not overwite existing file \"" << filename << "\""
|
||||||
<< "\"" << std::endl;
|
<< std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,10 +121,8 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen
|
||||||
std::cerr << "ERROR [libpng]: " << message << std::endl;
|
std::cerr << "ERROR [libpng]: " << message << std::endl;
|
||||||
};
|
};
|
||||||
|
|
||||||
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
png_structp png_ptr = png_create_write_struct(
|
||||||
nullptr,
|
PNG_LIBPNG_VER_STRING, nullptr, pngErrorLFn, pngWarnLFn);
|
||||||
pngErrorLFn,
|
|
||||||
pngWarnLFn);
|
|
||||||
|
|
||||||
if (png_ptr == nullptr) {
|
if (png_ptr == nullptr) {
|
||||||
fclose(outfile);
|
fclose(outfile);
|
||||||
|
@ -236,6 +215,7 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool image::Bl::writeToFile(file_type type, bool canOverwrite, const std::string &filename) {
|
bool image::Bl::writeToFile(file_type type, bool canOverwrite,
|
||||||
|
const std::string &filename) {
|
||||||
return writeToFile(type, canOverwrite, filename.c_str());
|
return writeToFile(type, canOverwrite, filename.c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
#define DITHERING_IMAGE_HPP
|
#define DITHERING_IMAGE_HPP
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace image {
|
namespace image {
|
||||||
enum class color_type {
|
enum class color_type {
|
||||||
|
@ -46,8 +46,10 @@ namespace image {
|
||||||
virtual int getTypeStride(color_type type) = 0;
|
virtual int getTypeStride(color_type type) = 0;
|
||||||
|
|
||||||
virtual bool canWriteFile(file_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,
|
||||||
virtual bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) = 0;
|
const char *filename) = 0;
|
||||||
|
virtual bool writeToFile(file_type type, bool canOverwrite,
|
||||||
|
const std::string &filename) = 0;
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,13 +82,16 @@ namespace image {
|
||||||
int getTypeStride(color_type) override { return 0; }
|
int getTypeStride(color_type) override { return 0; }
|
||||||
|
|
||||||
bool canWriteFile(file_type type) override;
|
bool canWriteFile(file_type type) override;
|
||||||
bool writeToFile(file_type type, bool canOverwrite, const char *filename) override;
|
bool writeToFile(file_type type, bool canOverwrite,
|
||||||
bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) override;
|
const char *filename) override;
|
||||||
|
bool writeToFile(file_type type, bool canOverwrite,
|
||||||
|
const std::string &filename) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
};
|
};
|
||||||
}
|
} // namespace image
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
18
src/main.cpp
18
src/main.cpp
|
@ -1,5 +1,5 @@
|
||||||
#include <iostream>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "arg_parse.hpp"
|
#include "arg_parse.hpp"
|
||||||
#include "blue_noise.hpp"
|
#include "blue_noise.hpp"
|
||||||
|
@ -13,13 +13,13 @@ int main(int argc, char **argv) {
|
||||||
// validation
|
// validation
|
||||||
if (args.generate_blue_noise_) {
|
if (args.generate_blue_noise_) {
|
||||||
if (args.output_filename_.empty()) {
|
if (args.output_filename_.empty()) {
|
||||||
std::cout << "ERROR: Cannot generate blue-noise, output filename is not specified"
|
std::cout << "ERROR: Cannot generate blue-noise, output filename "
|
||||||
|
"is not specified"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
Args::DisplayHelp();
|
Args::DisplayHelp();
|
||||||
return 1;
|
return 1;
|
||||||
} else if (args.blue_noise_size_ < 16) {
|
} else if (args.blue_noise_size_ < 16) {
|
||||||
std::cout << "ERROR: blue-noise size is too small"
|
std::cout << "ERROR: blue-noise size is too small" << std::endl;
|
||||||
<< std::endl;
|
|
||||||
Args::DisplayHelp();
|
Args::DisplayHelp();
|
||||||
return 1;
|
return 1;
|
||||||
} else if (!args.overwrite_file_) {
|
} else if (!args.overwrite_file_) {
|
||||||
|
@ -39,11 +39,11 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
if (args.generate_blue_noise_) {
|
if (args.generate_blue_noise_) {
|
||||||
std::cout << "Generating blue_noise..." << std::endl;
|
std::cout << "Generating blue_noise..." << std::endl;
|
||||||
image::Bl bl = dither::blue_noise(args.blue_noise_size_,
|
image::Bl bl =
|
||||||
args.blue_noise_size_,
|
dither::blue_noise(args.blue_noise_size_, args.blue_noise_size_,
|
||||||
args.threads_,
|
args.threads_, args.use_opencl_);
|
||||||
args.use_opencl_);
|
if (!bl.writeToFile(image::file_type::PNG, args.overwrite_file_,
|
||||||
if(!bl.writeToFile(image::file_type::PNG, args.overwrite_file_, args.output_filename_)) {
|
args.output_filename_)) {
|
||||||
std::cout << "ERROR: Failed to write blue-noise to file\n";
|
std::cout << "ERROR: Failed to write blue-noise to file\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#ifndef DITHERING_UTILITY_HPP
|
#ifndef DITHERING_UTILITY_HPP
|
||||||
#define DITHERING_UTILITY_HPP
|
#define DITHERING_UTILITY_HPP
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace utility {
|
namespace utility {
|
||||||
inline int twoToOne(int x, int y, int width, int height) {
|
inline int twoToOne(int x, int y, int width, int height) {
|
||||||
|
@ -28,6 +28,6 @@ namespace utility {
|
||||||
float dy = axy.second - bxy.second;
|
float dy = axy.second - bxy.second;
|
||||||
return std::sqrt(dx * dx + dy * dy);
|
return std::sqrt(dx * dx + dy * dy);
|
||||||
}
|
}
|
||||||
}
|
} // namespace utility
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue