Skip to content

Commit

Permalink
Checkpoint for non-square barcodes
Browse files Browse the repository at this point in the history
  • Loading branch information
sz3 committed Jul 22, 2024
1 parent b9668b5 commit 9febbad
Show file tree
Hide file tree
Showing 21 changed files with 147 additions and 99 deletions.
5 changes: 3 additions & 2 deletions src/exe/cimbar_send/send.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ int main(int argc, char** argv)
fps = defaultFps;
unsigned delay = 1000 / fps;

int window_size = cimbar::Config::image_size() + 32;
if (!initialize_GL(window_size, window_size))
int window_size_x = cimbar::Config::image_size_x() + 32;
int window_size_y = cimbar::Config::image_size_y() + 32;
if (!initialize_GL(window_size_x, window_size_y))
{
std::cerr << "failed to create window :(" << std::endl;
return 70;
Expand Down
17 changes: 11 additions & 6 deletions src/lib/cimb_translator/CimbReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ namespace {
}
cv::adaptiveThreshold(symbols, symbols, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, blockSize, 0);

bitbuffer bb(std::pow(Config::image_size(), 2) / 8);
// TODO: this should be on capacity, not image_size... right??
bitbuffer bb(Config::image_size_x() * Config::image_size_y() / 8);
bitmatrix::mat_to_bitbuffer(symbols, bb.get_writer());
return bb;
}
Expand All @@ -58,8 +59,9 @@ namespace {
if (dark)
{
unsigned tl = Config::anchor_size() - 2;
unsigned br = Config::image_size() - Config::anchor_size() - 2;
std::array<std::pair<unsigned, unsigned>, 3> anchors = {{ {tl, tl}, {tl, br}, {br, tl} }};
unsigned right = Config::image_size_x() - Config::anchor_size() - 2;
unsigned bottom = Config::image_size_y() - Config::anchor_size() - 2;
std::array<std::pair<unsigned, unsigned>, 3> anchors = {{ {tl, tl}, {tl, bottom}, {right, tl} }};
for (auto [x, y] : anchors)
{
cv::Rect crop(x, y, 4, 4);
Expand All @@ -69,9 +71,11 @@ namespace {
}
else // light
{
// TODO ONO: this is wrong, fix it
unsigned tl = (Config::anchor_size() << 1) + 6;
unsigned br = Config::image_size() - tl - 4;
std::array<std::pair<unsigned, unsigned>, 4> anchors = {{ {0, tl}, {tl, 0}, {0, br}, {br, 0} }};
unsigned right = Config::image_size_x() - tl - 4;
unsigned bottom = Config::image_size_y() - tl - 4;
std::array<std::pair<unsigned, unsigned>, 4> anchors = {{ {0, tl}, {tl, 0}, {0, bottom}, {right, 0} }};
for (auto [x, y] : anchors)
{
cv::Rect crop(x, y, 4, 4);
Expand All @@ -96,7 +100,7 @@ CimbReader::CimbReader(const cv::Mat& img, CimbDecoder& decoder, unsigned color_
, _cellSize(Config::cell_size() + 2)
, _positions(Config::cell_spacing_x(), Config::cell_spacing_y(), Config::cells_per_col_x(), Config::cells_per_col_y(), Config::cell_offset(), Config::corner_padding_x(), Config::corner_padding_y())
, _decoder(decoder)
, _good(_image.cols >= Config::image_size() and _image.rows >= Config::image_size())
, _good(_image.cols >= Config::image_size_x() and _image.rows >= Config::image_size_y())
, _colorCorrection(color_correction)
, _colorMode(color_mode)
{
Expand Down Expand Up @@ -172,6 +176,7 @@ void CimbReader::init_ccm(unsigned color_bits, unsigned interleave_blocks, unsig

//std::cout << fmt::format("fountain blocks={},capacity={}", fountain_blocks, cimbar::Config::capacity(_decoder.symbol_bits() + color_bits)) << std::endl;
//std::cout << fmt::format("fountain end={},headerstart={},headerlen={}", end, headerStartInterval, headerLen) << std::endl;
//std::cout << fmt::format("headerintervalcalc={},fountainblocks={}, color_bits={}", cimbar::Config::capacity(_decoder.symbol_bits() + color_bits), fountain_blocks, color_bits) << std::endl;

// get color map
std::unordered_map<uint16_t, std::tuple<unsigned, unsigned, unsigned, unsigned>> colors;
Expand Down
37 changes: 20 additions & 17 deletions src/lib/cimb_translator/CimbWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Config.h"
#include "serialize/format.h"
#include <string>
#include <iostream>
using std::string;

using namespace cimbar;
Expand Down Expand Up @@ -35,43 +36,45 @@ namespace {
}
}

CimbWriter::CimbWriter(unsigned symbol_bits, unsigned color_bits, bool dark, unsigned color_mode, int size)
CimbWriter::CimbWriter(unsigned symbol_bits, unsigned color_bits, bool dark, unsigned color_mode, int width, int height)
: _positions(Config::cell_spacing_x(), Config::cell_spacing_y(), Config::cells_per_col_x(), Config::cells_per_col_y(), Config::cell_offset(), Config::corner_padding_x(), Config::corner_padding_y(), Config::interleave_blocks(), Config::interleave_partitions())
, _encoder(symbol_bits, color_bits, dark, color_mode)
{
if (size > cimbar::Config::image_size())
_offset = (size - cimbar::Config::image_size()) / 2;
else
size = cimbar::Config::image_size();
height = std::max(height, cimbar::Config::image_size_y());
width = std::max(width, cimbar::Config::image_size_x());

_offsetX = (width - cimbar::Config::image_size_x()) / 2;
_offsetY = (height - cimbar::Config::image_size_y()) / 2;

cv::Scalar bgcolor = dark? cv::Scalar(0, 0, 0) : cv::Scalar(0xFF, 0xFF, 0xFF);
_image = cv::Mat(size, size, CV_8UC3, bgcolor);
_image = cv::Mat(height, width, CV_8UC3, bgcolor);

// from here on, we only care about the internal size
size = cimbar::Config::image_size();
width = cimbar::Config::image_size_x();
height = cimbar::Config::image_size_y();

cv::Mat anchor = getAnchor(dark);
paste(anchor, 0, 0);
paste(anchor, 0, size - anchor.cols);
paste(anchor, size - anchor.rows, 0);
paste(anchor, 0, height - anchor.rows);
paste(anchor, width - anchor.cols, 0);

cv::Mat secondaryAnchor = getSecondaryAnchor(dark);
paste(secondaryAnchor, size - anchor.rows, size - anchor.cols);
paste(secondaryAnchor, width - anchor.cols, height - anchor.rows);

cv::Mat hg = getHorizontalGuide(dark);
paste(hg, (size/2) - (hg.cols/2), 2);
paste(hg, (size/2) - (hg.cols/2), size-4);
paste(hg, (size/2) - (hg.cols/2) - hg.cols, size-4);
paste(hg, (size/2) - (hg.cols/2) + hg.cols, size-4);
paste(hg, (width/2) - (hg.cols/2), 2);
paste(hg, (width/2) - (hg.cols/2), height-4);
paste(hg, (width/2) - (hg.cols/2) - hg.cols, height-4);
paste(hg, (width/2) - (hg.cols/2) + hg.cols, height-4);

cv::Mat vg = getVerticalGuide(dark);
paste(vg, 2, (size/2) - (vg.rows/2));
paste(vg, size-4, (size/2) - (vg.rows/2));
paste(vg, 2, (height/2) - (vg.rows/2));
paste(vg, width-4, (height/2) - (vg.rows/2));
}

void CimbWriter::paste(const cv::Mat& img, int x, int y)
{
img.copyTo(_image(cv::Rect(x+_offset, y+_offset, img.cols, img.rows)));
img.copyTo(_image(cv::Rect(x+_offsetX, y+_offsetY, img.cols, img.rows)));
}

bool CimbWriter::write(unsigned bits)
Expand Down
5 changes: 3 additions & 2 deletions src/lib/cimb_translator/CimbWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class CimbWriter
{
public:
CimbWriter(unsigned symbol_bits, unsigned color_bits, bool dark=true, unsigned color_mode=1, int size=0);
CimbWriter(unsigned symbol_bits, unsigned color_bits, bool dark=true, unsigned color_mode=1, int width=0, int height=0);

bool write(unsigned bits);
bool done() const;
Expand All @@ -23,5 +23,6 @@ class CimbWriter
cv::Mat _image;
CellPositions _positions;
CimbEncoder _encoder;
unsigned _offset = 0;
unsigned _offsetX = 0;
unsigned _offsetY = 0;
};
17 changes: 7 additions & 10 deletions src/lib/cimb_translator/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace {
RGB(0, 0xFF, 0),
RGB(0, 0xFF, 0xFF),
RGB(0xFF, 0xFF, 0),
RGB(0xFF, 0x55, 0xFF), // 0x55
RGB(0xFF, 0, 0xFF), // RGB(0xFF, 0x55, 0xFF),
};
return colors[index];
}
Expand Down Expand Up @@ -75,9 +75,9 @@ namespace {
{
// opencv uses BGR, but we don't have to conform to its tyranny
static constexpr array<RGB, 4> colors = {
RGB(0, 0x20, 0),
RGB(0, 0, 0xFF),
RGB(0x7F, 0, 0),
RGB(0, 0, 0), //RGB(0, 0x20, 0),
RGB(0, 0, 0),//RGB(0, 0, 0xFF),
RGB(0, 0, 0), //RGB(0x7F, 0, 0),
RGB(0, 0, 0),
};
return colors[index];
Expand Down Expand Up @@ -125,9 +125,6 @@ RGB getColor(unsigned index, unsigned num_colors, unsigned color_mode)

RGB getBgColor(unsigned index, unsigned num_colors, unsigned color_mode)
{
// light mode
if (color_mode >= 100)
return RGB(0xFF, 0xFF, 0xFF);

if (color_mode == 1 and num_colors <= 4)
return getBgColor4(index);
Expand All @@ -150,10 +147,10 @@ cv::Mat getTile(unsigned symbol_bits, unsigned symbol, bool dark, unsigned num_c
for (cv::MatIterator_<cv::Vec3b> it = tile.begin<cv::Vec3b>(); it != end; ++it)
{
cv::Vec3b& c = *it;
if (c == background)
c = {bgr, bgg, bgb};
else
if (c != background)
c = {r, g, b};
else if (dark)
c = {bgr, bgg, bgb};
}
return tile;
}
Expand Down
11 changes: 8 additions & 3 deletions src/lib/cimb_translator/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace cimbar
class Config
{
protected:
using GridConf = Conf5x5d;
using GridConf = Conf8x8;

public:
static constexpr bool dark()
Expand Down Expand Up @@ -46,9 +46,14 @@ namespace cimbar
return GridConf::ecc_block_size;
}

static constexpr int image_size()
static constexpr int image_size_x()
{
return GridConf::image_size;
return GridConf::image_size_x;
}

static constexpr int image_size_y()
{
return GridConf::image_size_y;
}

static constexpr unsigned anchor_size()
Expand Down
9 changes: 6 additions & 3 deletions src/lib/cimb_translator/GridConf.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ namespace cimbar
static constexpr unsigned symbol_bits = 2;
static constexpr unsigned ecc_bytes = 40;
static constexpr unsigned ecc_block_size = 216;
static constexpr int image_size = 988;
static constexpr int image_size_x = 988;
static constexpr int image_size_y = image_size_x;

static constexpr unsigned cell_size = 5;
static constexpr unsigned cell_spacing_x = cell_size+1;
Expand All @@ -27,7 +28,8 @@ namespace cimbar
static constexpr unsigned symbol_bits = 2;
static constexpr unsigned ecc_bytes = 35;
static constexpr unsigned ecc_block_size = 182;
static constexpr int image_size = 958;
static constexpr int image_size_x = 958;
static constexpr int image_size_y = image_size_x;

static constexpr unsigned cell_size = 5;
static constexpr unsigned cell_spacing_x = cell_size;
Expand All @@ -45,7 +47,8 @@ namespace cimbar
static constexpr unsigned symbol_bits = 4;
static constexpr unsigned ecc_bytes = 30;
static constexpr unsigned ecc_block_size = 155;
static constexpr int image_size = 1024;
static constexpr int image_size_x = 1024;
static constexpr int image_size_y = image_size_x;

static constexpr unsigned cell_size = 8;
static constexpr unsigned cell_spacing_x = cell_size+1;
Expand Down
18 changes: 17 additions & 1 deletion src/lib/cimb_translator/test/CimbWriterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ TEST_CASE( "CimbWriterTest/testSimple", "[unit]" )

TEST_CASE( "CimbWriterTest/testCustomSize", "[unit]" )
{
CimbWriter cw(4, 2, true, 1, 1040);
CimbWriter cw(4, 2, true, 1, 1040, 1040);

while (1)
{
Expand All @@ -40,3 +40,19 @@ TEST_CASE( "CimbWriterTest/testCustomSize", "[unit]" )
assertEquals(1040, img.rows);
assertEquals( 0xab00ab02af0abfab, image_hash::average_hash(img) );
}

TEST_CASE( "CimbWriterTest/testCustomSize.2", "[unit]" )
{
CimbWriter cw(4, 2, true, 1, 1040, 1080);

while (1)
{
if (!cw.write(0))
break;
}

cv::Mat img = cw.image();
assertEquals(1040, img.cols);
assertEquals(1080, img.rows);
assertEquals( 0xab2a2a2a2a2a2aab, image_hash::average_hash(img) );
}
2 changes: 1 addition & 1 deletion src/lib/cimbar_js/cimbar_js.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ int next_frame()
enc.set_legacy_mode();

enc.set_encode_id(_encodeId);
_next = enc.encode_next(*_fes, _window->width());
_next = enc.encode_next(*_fes, _window->width(), _window->height());
return ++_frameCount;
}

Expand Down
12 changes: 6 additions & 6 deletions src/lib/encoder/Encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class Encoder : public SimpleEncoder
using SimpleEncoder::SimpleEncoder;

unsigned encode(const std::string& filename, std::string output_prefix);
unsigned encode_fountain(const std::string& filename, std::string output_prefix, int compression_level=16, double redundancy=1.2, int canvas_size=0);
unsigned encode_fountain(const std::string& filename, const std::function<bool(const cv::Mat&, unsigned)>& on_frame, int compression_level=16, double redundancy=4.0, int canvas_size=0);
unsigned encode_fountain(const std::string& filename, std::string output_prefix, int compression_level=16, double redundancy=1.2);
unsigned encode_fountain(const std::string& filename, const std::function<bool(const cv::Mat&, unsigned)>& on_frame, int compression_level=16, double redundancy=4.0);
};

inline unsigned Encoder::encode(const std::string& filename, std::string output_prefix)
Expand All @@ -39,7 +39,7 @@ inline unsigned Encoder::encode(const std::string& filename, std::string output_
return i;
}

inline unsigned Encoder::encode_fountain(const std::string& filename, const std::function<bool(const cv::Mat&, unsigned)>& on_frame, int compression_level, double redundancy, int canvas_size)
inline unsigned Encoder::encode_fountain(const std::string& filename, const std::function<bool(const cv::Mat&, unsigned)>& on_frame, int compression_level, double redundancy)
{
std::ifstream infile(filename);
fountain_encoder_stream::ptr fes = create_fountain_encoder(infile, compression_level);
Expand All @@ -57,7 +57,7 @@ inline unsigned Encoder::encode_fountain(const std::string& filename, const std:
unsigned i = 0;
while (i < requiredFrames)
{
auto frame = encode_next(*fes, canvas_size);
auto frame = encode_next(*fes);
if (!frame)
break;

Expand All @@ -68,13 +68,13 @@ inline unsigned Encoder::encode_fountain(const std::string& filename, const std:
return i;
}

inline unsigned Encoder::encode_fountain(const std::string& filename, std::string output_prefix, int compression_level, double redundancy, int canvas_size)
inline unsigned Encoder::encode_fountain(const std::string& filename, std::string output_prefix, int compression_level, double redundancy)
{
std::function<bool(const cv::Mat&, unsigned)> fun = [output_prefix] (const cv::Mat& frame, unsigned i) {
std::string output = fmt::format("{}_{}.png", output_prefix, i);
cv::Mat bgr;
cv::cvtColor(frame, bgr, cv::COLOR_RGB2BGR);
return cv::imwrite(output, bgr);
};
return encode_fountain(filename, fun, compression_level, redundancy, canvas_size);
return encode_fountain(filename, fun, compression_level, redundancy);
}
14 changes: 7 additions & 7 deletions src/lib/encoder/SimpleEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ class SimpleEncoder
void set_encode_id(uint8_t encode_id); // [0-127] -- the high bit is ignored.

template <typename STREAM>
std::optional<cv::Mat> encode_next(STREAM& stream, int canvas_size=0);
std::optional<cv::Mat> encode_next(STREAM& stream, int canvas_width=0, int canvas_height=0);

template <typename STREAM>
fountain_encoder_stream::ptr create_fountain_encoder(STREAM& stream, int compression_level=6);

protected:
template <typename STREAM>
std::optional<cv::Mat> encode_next_coupled(STREAM& stream, int canvas_size=0);
std::optional<cv::Mat> encode_next_coupled(STREAM& stream, int canvas_width=0, int canvas_height=0);

protected:
unsigned _eccBytes;
Expand Down Expand Up @@ -64,16 +64,16 @@ inline void SimpleEncoder::set_encode_id(uint8_t encode_id)
}

template <typename STREAM>
inline std::optional<cv::Mat> SimpleEncoder::encode_next(STREAM& stream, int canvas_size)
inline std::optional<cv::Mat> SimpleEncoder::encode_next(STREAM& stream, int canvas_width, int canvas_height)
{
if (_coupled)
return encode_next_coupled(stream, canvas_size);
return encode_next_coupled(stream, canvas_width, canvas_height);

if (!stream.good())
return std::nullopt;

unsigned bits_per_op = _bitsPerColor + _bitsPerSymbol;
CimbWriter writer(_bitsPerSymbol, _bitsPerColor, _dark, _colorMode, canvas_size);
CimbWriter writer(_bitsPerSymbol, _bitsPerColor, _dark, _colorMode, canvas_width, canvas_height);

unsigned numCells = writer.num_cells();
bitbuffer bb(cimbar::Config::capacity(bits_per_op));
Expand Down Expand Up @@ -127,7 +127,7 @@ inline std::optional<cv::Mat> SimpleEncoder::encode_next(STREAM& stream, int can
}

template <typename STREAM>
inline std::optional<cv::Mat> SimpleEncoder::encode_next_coupled(STREAM& stream, int canvas_size)
inline std::optional<cv::Mat> SimpleEncoder::encode_next_coupled(STREAM& stream, int canvas_width, int canvas_height)
{
// the old way. Symbol and color bits are mixed together, limiting the color correction possibilities
// but potentially allowing a lack of errors in one channel to correct errors in the other.
Expand All @@ -138,7 +138,7 @@ inline std::optional<cv::Mat> SimpleEncoder::encode_next_coupled(STREAM& stream,
return std::nullopt;

unsigned bits_per_op = _bitsPerColor + _bitsPerSymbol;
CimbWriter writer(_bitsPerSymbol, _bitsPerColor, _dark, _colorMode, canvas_size);
CimbWriter writer(_bitsPerSymbol, _bitsPerColor, _dark, _colorMode, canvas_width, canvas_height);

reed_solomon_stream rss(stream, _eccBytes, _eccBlockSize);
bitreader br;
Expand Down
Loading

0 comments on commit 9febbad

Please sign in to comment.