Fix image::Bl write, use image::Bl as result for blue_noise

This commit is contained in:
Stephen Seo 2021-02-11 11:33:14 +09:00
parent 5155b847ca
commit 5826c3677c
6 changed files with 134 additions and 82 deletions

View file

@ -9,7 +9,8 @@ endif
SOURCES= \
src/main.cpp \
src/blue_noise.cpp
src/blue_noise.cpp \
src/image.cpp
OBJECTS=${subst .cpp,.o,${SOURCES}}
all: Dithering

View file

@ -12,87 +12,90 @@
# include <cstdio>
#endif
std::vector<bool> dither::blue_noise(int width, int height, int threads) {
image::Bl dither::blue_noise(int width, int height, int threads, bool use_opencl) {
bool use_opencl = false;
bool using_opencl = false;
// try to use OpenCL
do {
cl_device_id device;
cl_context context;
cl_program program;
cl_int err;
if(use_opencl) {
// try to use OpenCL
do {
cl_device_id device;
cl_context context;
cl_program program;
cl_int err;
cl_platform_id platform;
cl_platform_id platform;
int filter_size = (width + height) / 2;
int filter_size = (width + height) / 2;
err = clGetPlatformIDs(1, &platform, nullptr);
if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to identify a platform\n";
break;
}
err = clGetPlatformIDs(1, &platform, nullptr);
if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to identify a platform\n";
break;
}
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, nullptr);
if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to get a device\n";
break;
}
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, nullptr);
if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to get a device\n";
break;
}
context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
{
char buf[1024];
std::ifstream program_file("src/blue_noise.cl");
std::string program_string;
while(program_file.good()) {
program_file.read(buf, 1024);
if(int read_count = program_file.gcount(); read_count > 0) {
program_string.append(buf, read_count);
{
char buf[1024];
std::ifstream program_file("src/blue_noise.cl");
std::string program_string;
while(program_file.good()) {
program_file.read(buf, 1024);
if(int read_count = program_file.gcount(); read_count > 0) {
program_string.append(buf, read_count);
}
}
const char *string_ptr = program_string.c_str();
std::size_t program_size = program_string.size();
program = clCreateProgramWithSource(context, 1, (const char**)&string_ptr, &program_size, &err);
if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to create the program\n";
clReleaseContext(context);
break;
}
err = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);
if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to build the program\n";
std::size_t log_size;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size);
std::unique_ptr<char[]> log = std::make_unique<char[]>(log_size + 1);
log[log_size] = 0;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, log.get(), nullptr);
std::cerr << log.get() << std::endl;
clReleaseProgram(program);
clReleaseContext(context);
break;
}
}
const char *string_ptr = program_string.c_str();
std::size_t program_size = program_string.size();
program = clCreateProgramWithSource(context, 1, (const char**)&string_ptr, &program_size, &err);
if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to create the program\n";
clReleaseContext(context);
break;
std::cout << "OpenCL: Initialized, trying cl_impl..." << std::endl;
std::vector<bool> result = internal::blue_noise_cl_impl(
width, height, filter_size, context, device, program);
clReleaseProgram(program);
clReleaseContext(context);
if(!result.empty()) {
return internal::toBl(result, width);
}
} while (false);
}
err = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);
if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to build the program\n";
std::size_t log_size;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size);
std::unique_ptr<char[]> log = std::make_unique<char[]>(log_size + 1);
log[log_size] = 0;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, log.get(), nullptr);
std::cerr << log.get() << std::endl;
clReleaseProgram(program);
clReleaseContext(context);
break;
}
}
std::cout << "OpenCL: Initialized, trying cl_impl..." << std::endl;
std::vector<bool> result = internal::blue_noise_cl_impl(
width, height, filter_size, context, device, program);
clReleaseProgram(program);
clReleaseContext(context);
if(!result.empty()) {
return result;
}
} while (false);
if(!use_opencl) {
std::cout << "OpenCL: Failed to setup/use, using regular impl..." << std::endl;
return internal::blue_noise_impl(width, height, threads);
if(!using_opencl) {
std::cout << "OpenCL: Failed to setup/use or is not enabled, using regular impl..."
<< std::endl;
return internal::toBl(internal::blue_noise_impl(width, height, threads), width);
}
return {};

View file

@ -11,14 +11,16 @@
#include <cstdio>
#include <queue>
#include <random>
#include <cassert>
#include <CL/opencl.h>
#include "utility.hpp"
#include "image.hpp"
namespace dither {
std::vector<bool> blue_noise(int width, int height, int threads = 1);
image::Bl blue_noise(int width, int height, int threads = 1, bool use_opencl = true);
namespace internal {
std::vector<bool> blue_noise_impl(int width, int height, int threads = 1);
@ -311,6 +313,18 @@ namespace internal {
}
fclose(filter_image);
}
inline image::Bl toBl(const std::vector<bool>& pbp, int width) {
image::Bl bwImage(width, pbp.size() / width);
assert((unsigned long)bwImage.getSize() >= pbp.size()
&& "New image::Bl size too small (pbp's size is not a multiple of width)");
for(unsigned int i = 0; i < pbp.size(); ++i) {
bwImage.getData()[i] = pbp[i] ? 1 : 0;
}
return bwImage;
}
} // namespace dither::internal
} // namespace dither

View file

@ -3,6 +3,12 @@
#include <cstdio>
#include <random>
image::Bl::Bl() :
data(),
width(0),
height(0)
{}
image::Bl::Bl(int width, int height) :
data(width * height),
width(width),
@ -22,6 +28,10 @@ height(data.size() / width)
{}
void image::Bl::randomize() {
if(!isValid()) {
return;
}
std::default_random_engine re(std::random_device{}());
std::uniform_int_distribution<unsigned int> dist;
@ -42,10 +52,23 @@ int image::Bl::getSize() {
}
uint8_t* image::Bl::getData() {
if(!isValid()) {
return nullptr;
}
return &data[0];
}
const uint8_t* image::Bl::getDataC() const {
if(!isValid()) {
return nullptr;
}
return &data[0];
}
bool image::Bl::canWriteFile(file_type type) {
if(!isValid()) {
return false;
}
switch(type) {
case file_type::PBM:
case file_type::PGM:
@ -57,7 +80,7 @@ bool image::Bl::canWriteFile(file_type type) {
}
bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filename) {
if(!canWriteFile(type)) {
if(!isValid() || !canWriteFile(type)) {
return false;
}
@ -66,7 +89,10 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen
fclose(file);
return false;
}
fclose(file);
if(file) {
fclose(file);
}
switch(type) {
case file_type::PBM:
@ -112,3 +138,7 @@ 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;
}

View file

@ -21,22 +21,22 @@ namespace image {
// TODO PNG support
};
class base {
class Base {
public:
base() = default;
virtual ~base() {}
Base() = default;
virtual ~Base() {}
base(const base &other) = default;
base(base &&other) = default;
Base(const Base &other) = default;
Base(Base &&other) = default;
base& operator=(const base &other) = default;
base& operator=(base &&other) = default;
Base& operator=(const Base &other) = default;
Base& operator=(Base &&other) = default;
virtual void randomize() = 0;
virtual int getSize() = 0;
virtual uint8_t* getData() = 0;
virtual const uint8_t* getDataC() { return getData(); }
virtual const uint8_t* getDataC() const = 0;
virtual int getTypesCount() = 0;
virtual std::vector<color_type> getTypes() = 0;
@ -47,8 +47,9 @@ namespace image {
virtual bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) = 0;
};
class Bl : public base {
class Bl : public Base {
public:
Bl();
Bl(int width, int height);
Bl(const std::vector<uint8_t> &data, int width);
Bl(std::vector<uint8_t> &&data, int width);
@ -64,6 +65,7 @@ namespace image {
virtual int getSize() override;
virtual uint8_t* getData() override;
virtual const uint8_t* getDataC() const override;
virtual int getTypesCount() override { return 1; }
virtual std::vector<color_type> getTypes() override { return { color_type::Black }; }
@ -72,6 +74,7 @@ namespace image {
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;
private:
std::vector<uint8_t> data;
int width;

View file

@ -5,7 +5,8 @@
int main(int argc, char **argv) {
//#ifndef NDEBUG
std::cout << "Trying blue_noise..." << std::endl;
dither::blue_noise(100, 100, 8);
image::Bl bl = dither::blue_noise(100, 100, 8, true);
bl.writeToFile(image::file_type::PBM, true, "blueNoiseOut.pbm");
//#endif
return 0;