genesys: Implement image pipeline for merging color channels to gray

merge-requests/673/head
Povilas Kanapickas 2021-12-27 22:21:02 +02:00
rodzic ad84284186
commit 2f030f04e2
3 zmienionych plików z 128 dodań i 0 usunięć

Wyświetl plik

@ -417,6 +417,75 @@ PixelFormat ImagePipelineNodeSplitMonoLines::get_output_format(PixelFormat input
throw SaneException("Unsupported input format %d", static_cast<unsigned>(input_format));
}
ImagePipelineNodeMergeColorToGray::ImagePipelineNodeMergeColorToGray(ImagePipelineNode& source) :
source_(source)
{
output_format_ = get_output_format(source_.get_format());
float red_mult = 0.2125f;
float green_mult = 0.7154f;
float blue_mult = 0.0721f;
switch (get_pixel_format_color_order(source_.get_format())) {
case ColorOrder::RGB: {
ch0_mult_ = red_mult;
ch1_mult_ = green_mult;
ch2_mult_ = blue_mult;
break;
}
case ColorOrder::BGR: {
ch0_mult_ = blue_mult;
ch1_mult_ = green_mult;
ch2_mult_ = red_mult;
break;
}
case ColorOrder::GBR: {
ch0_mult_ = green_mult;
ch1_mult_ = blue_mult;
ch2_mult_ = red_mult;
break;
}
default:
throw SaneException("Unknown color order");
}
temp_buffer_.resize(source_.get_row_bytes());
}
bool ImagePipelineNodeMergeColorToGray::get_next_row_data(std::uint8_t* out_data)
{
auto* src_data = temp_buffer_.data();
bool got_data = source_.get_next_row_data(src_data);
auto src_format = source_.get_format();
for (std::size_t x = 0, width = get_width(); x < width; ++x) {
std::uint16_t ch0 = get_raw_channel_from_row(src_data, x, 0, src_format);
std::uint16_t ch1 = get_raw_channel_from_row(src_data, x, 1, src_format);
std::uint16_t ch2 = get_raw_channel_from_row(src_data, x, 2, src_format);
float mono = ch0 * ch0_mult_ + ch1 * ch1_mult_ + ch2 * ch2_mult_;
set_raw_channel_to_row(out_data, x, 0, static_cast<std::uint16_t>(mono), output_format_);
}
return got_data;
}
PixelFormat ImagePipelineNodeMergeColorToGray::get_output_format(PixelFormat input_format)
{
switch (input_format) {
case PixelFormat::RGB111:
return PixelFormat::I1;
case PixelFormat::RGB888:
case PixelFormat::BGR888:
return PixelFormat::I8;
case PixelFormat::RGB161616:
case PixelFormat::BGR161616:
return PixelFormat::I16;
default: break;
}
throw SaneException("Unsupported format %d", static_cast<unsigned>(input_format));
}
ImagePipelineNodeComponentShiftLines::ImagePipelineNodeComponentShiftLines(
ImagePipelineNode& source, unsigned shift_r, unsigned shift_g, unsigned shift_b) :
source_(source),

Wyświetl plik

@ -342,6 +342,33 @@ private:
unsigned next_channel_ = 0;
};
// A pipeline node that merges 3 mono lines into a gray channel
class ImagePipelineNodeMergeColorToGray : public ImagePipelineNode
{
public:
ImagePipelineNodeMergeColorToGray(ImagePipelineNode& source);
std::size_t get_width() const override { return source_.get_width(); }
std::size_t get_height() const override { return source_.get_height(); }
PixelFormat get_format() const override { return output_format_; }
bool eof() const override { return source_.eof(); }
bool get_next_row_data(std::uint8_t* out_data) override;
private:
static PixelFormat get_output_format(PixelFormat input_format);
ImagePipelineNode& source_;
PixelFormat output_format_ = PixelFormat::UNKNOWN;
float ch0_mult_ = 0;
float ch1_mult_ = 0;
float ch2_mult_ = 0;
std::vector<std::uint8_t> temp_buffer_;
};
// A pipeline node that shifts colors across lines by the given offsets
class ImagePipelineNodeComponentShiftLines : public ImagePipelineNode
{

Wyświetl plik

@ -500,6 +500,37 @@ void test_node_merge_mono_lines_to_color()
ASSERT_EQ(out_data, expected_data);
}
void test_node_merge_color_to_gray()
{
using Data = std::vector<std::uint8_t>;
Data in_data = {
0x10, 0x20, 0x30, 0x11, 0x21, 0x31,
0x12, 0x22, 0x32, 0x13, 0x23, 0x33,
0x14, 0x24, 0x34, 0x15, 0x25, 0x35,
0x16, 0x26, 0x36, 0x17, 0x27, 0x37,
};
ImagePipelineStack stack;
stack.push_first_node<ImagePipelineNodeArraySource>(8, 1, PixelFormat::RGB888,
std::move(in_data));
stack.push_node<ImagePipelineNodeMergeColorToGray>();
ASSERT_EQ(stack.get_output_width(), 8u);
ASSERT_EQ(stack.get_output_height(), 1u);
ASSERT_EQ(stack.get_output_row_bytes(), 8u);
ASSERT_EQ(stack.get_output_format(), PixelFormat::I8);
auto out_data = stack.get_all_data();
Data expected_data = {
0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24
};
ASSERT_EQ(out_data, expected_data);
}
void test_node_split_mono_lines()
{
using Data = std::vector<std::uint8_t>;
@ -938,6 +969,7 @@ void test_image_pipeline()
test_node_invert_8_bits();
test_node_invert_1_bits();
test_node_merge_mono_lines_to_color();
test_node_merge_color_to_gray();
test_node_split_mono_lines();
test_node_component_shift_lines();
test_node_pixel_shift_columns_no_switch();