aboutsummaryrefslogtreecommitdiff
path: root/signature.cpp
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2022-09-18 01:52:26 -0400
committerGravatar Chris Xiong <chirs241097@gmail.com> 2022-09-18 01:52:26 -0400
commit4401f681d33f534a7d7ef8f4f940bd54b60710c3 (patch)
treed393f5fa9b5c7e96eae94e3986c40f9d80777818 /signature.cpp
parentf02cb7bf4978ec0fa1eea4ed0b21460b7637d741 (diff)
downloaddeduper-4401f681d33f534a7d7ef8f4f940bd54b60710c3.tar.xz
Move stuff around to accommodate new family members.
Diffstat (limited to 'signature.cpp')
-rw-r--r--signature.cpp338
1 files changed, 0 insertions, 338 deletions
diff --git a/signature.cpp b/signature.cpp
deleted file mode 100644
index b912198..0000000
--- a/signature.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-//Chris Xiong 2022
-//License: MPL-2.0
-/* Based on
- * H. Chi Wong, M. Bern and D. Goldberg,
- * "An image signature for any kind of image," Proceedings.
- * International Conference on Image Processing, 2002, pp. I-I,
- * doi: 10.1109/ICIP.2002.1038047.
- * and
- * libpuzzle (also an implementation of the article above).
- */
-#include "signature.hpp"
-
-#include <algorithm>
-#include <fstream>
-#include <cmath>
-#include <cstdint>
-#include <vector>
-
-#include <opencv2/core.hpp>
-#include <opencv2/imgcodecs.hpp>
-#include <opencv2/imgproc.hpp>
-
-#include "compressed_vector.hpp"
-#include "imageutil.hpp"
-
-static signature_config _default_cfg =
-{
- 9, //slices
- 3, //blur_window
- 2, //min_window
- true, //crop
- false, //comp
- 0.5, //pr
- 1./128,//noise_threshold
- 0.05, //contrast_threshold
- 0.25 //max_cropping
-};
-
-class signature_priv
-{
-private:
- cv::Mat fimg;
- cv::Mat lch;
- std::vector<float> lv;
- compressed_vector<uint8_t, 3> ct;
- std::vector<uint8_t> uct;
- bool compressed;
- signature_config cfg;
-public:
- float get_light_charistics_cell(int x, int y, int w, int h);
- void get_light_charistics();
- void get_light_variance();
- void get_signature();
- double length() const;
- double distance(const signature_priv &o) const;
- bool operator==(const signature_priv &o) const;
- void dump() const;
- friend class signature;
- friend struct signature_hash;
-};
-
-float signature_priv::get_light_charistics_cell(int x, int y, int w, int h)
-{
- return cv::mean(fimg(cv::Range(y, y + h), cv::Range(x, x + w)))[0];
-}
-
-void signature_priv::get_light_charistics()
-{
- double windowx, windowy;
- int iw, ih, slc;
- iw = fimg.size().width;
- ih = fimg.size().height;
- slc = cfg.slices;
- windowx = iw / (double)slc / 2;
- windowy = ih / (double)slc / 2;
- int windows = round(std::min(iw, ih) / slc * cfg.pr);
- if (windows < cfg.min_window)
- windows = cfg.min_window;
- double ww = (iw - 1) / (slc + 1.);
- double wh = (ih - 1) / (slc + 1.);
- double wxs = 0, wys = 0;
- if (windows < ww) wxs = (ww - windows) / 2.;
- if (windows < wh) wys = (wh - windows) / 2.;
- lch.create(slc, slc, CV_32F);
- float *lp = lch.ptr<float>(0);
- for (int i = 0; i < slc; ++i)
- {
- for (int j = 0; j < slc; ++j)
- {
- double cwx, cwy;
- cwx = i * (iw - 1) / (slc + 1.) + windowx;
- cwy = j * (ih - 1) / (slc + 1.) + windowy;
- int x = (int)round(cwx + wxs);
- int y = (int)round(cwy + wys);
- int cww, cwh;
- cww = (iw - x < windows) ? 1 : windows;
- cwh = (ih - y < windows) ? 1 : windows;
- *(lp++) = get_light_charistics_cell(x, y, cww, cwh);
- }
- }
-}
-
-void signature_priv::get_light_variance()
-{
- const int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
- const int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
- int slc = cfg.slices;
- float *lp = lch.ptr<float>(0);
- for (int x = 0; x < slc; ++x)
- {
- for (int y = 0; y < slc; ++y)
- {
- for (int k = 0; k < 8; ++k)
- {
- int nx = x + dx[k];
- int ny = y + dy[k];
- if (nx < 0 || ny < 0 || nx >= slc || ny >= slc)
- lv.push_back(0);
- else
- lv.push_back(*lp - *(lp + dx[k] * slc + dy[k]));
- }
- ++lp;
- }
- }
-}
-
-void signature_priv::get_signature()
-{
- std::vector<double> lights;
- std::vector<double> darks;
- for (float &l : lv)
- {
- if (fabsf(l) > cfg.noise_threshold)
- {
- if (l > 0)
- lights.push_back(l);
- else
- darks.push_back(l);
- }
- }
- double lth = image_util::median(lights);
- double dth = image_util::median(darks);
- if (cfg.compress)
- {
- compressed = true;
- for (float &l : lv)
- {
- if (fabsf(l) > cfg.noise_threshold)
- {
- if (l > 0)
- ct.push_back(l > lth ? 4 : 3);
- else
- ct.push_back(l < dth ? 0 : 1);
- }
- else ct.push_back(2);
- }
- }
- else
- {
- compressed = false;
- for (float &l : lv)
- {
- if (fabsf(l) > cfg.noise_threshold)
- {
- if (l > 0)
- uct.push_back(l > lth ? 4 : 3);
- else
- uct.push_back(l < dth ? 0 : 1);
- }
- else uct.push_back(2);
- }
- }
-}
-
-double signature_priv::length() const
-{
- if (compressed)
- return image_util::length(ct, (uint8_t)2);
- else
- return image_util::length(uct, 2);
-}
-
-double signature_priv::distance(const signature_priv &o) const
-{
- if (compressed && o.compressed)
- return image_util::distance(ct, o.ct) / (image_util::length(ct, uint8_t(2)) + image_util::length(o.ct, uint8_t(2)));
- else
- return image_util::distance(uct, o.uct) / (image_util::length(uct, uint8_t(2)) + image_util::length(o.uct, uint8_t(2)));
-}
-
-bool signature_priv::operator==(const signature_priv &o) const
-{
- if (compressed && o.compressed)
- return ct == o.ct;
- else
- return uct == o.uct;
-}
-
-void signature_priv::dump() const
-{
- if (!compressed)
- for (auto &x : this->uct)
- printf("%u ", x);
- else
- for (size_t i = 0; i < this->ct.size(); ++i)
- printf("%u ", this->ct.get(i));
- printf("\n");
-}
-
-signature::signature() = default;
-signature::signature(signature_priv* _p) : p(_p){}
-signature::~signature() = default;
-
-void signature::dump() const
-{
- if (p) p->dump();
-}
-
-bool signature::valid() const
-{return (bool)p;}
-
-signature signature::clone() const
-{
- return signature(*this);
-}
-
-double signature::length() const
-{
- if (!p) {fprintf(stderr, "length: null signature"); return -1;}
- return p->length();
-}
-
-double signature::distance(const signature &o) const
-{
- if (!p || !o.p) {fprintf(stderr, "distance: null signature"); return -1;}
- return p->distance(*o.p);
-}
-
-bool signature::operator==(const signature &o) const
-{
- if (!p || !o.p) {fprintf(stderr, "eq: null signature"); return false;}
- return *p == *o.p;
-}
-
-std::string signature::to_string() const
-{
- if (!p || !p->compressed) return std::string();
- Base64Encoder enc;
- size_t sz = p->ct.size();
- enc.encode_data(&p->cfg, sizeof(signature_config));
- enc.encode_data(&sz, sizeof(size_t));
- enc.encode_data(p->ct.internal_data(), p->ct.internal_container_size() * 8);
- return enc.finalize();
-}
-
-signature signature::from_string(std::string &&s)
-{
- signature_priv *p = new signature_priv;
- Base64Decoder dec(std::move(s));
- size_t sz;
- p->compressed = true;
- size_t s1 = dec.decode_data(&p->cfg, sizeof(signature_config));
- size_t s2 = dec.decode_data(&sz, sizeof(size_t));
- size_t s3 = dec.decoded_length() - s1 - s2;
- p->ct.internal_set_size(sz);
- p->ct.internal_container_resize(s3 / 8);
- dec.decode_data(p->ct.internal_data(), s3);
- return signature(p);
-}
-
-signature signature::from_preprocessed_matrix(cv::Mat *m, const signature_config &cfg)
-{
- signature_priv *p = new signature_priv;
- p->cfg = cfg;
-
- if (cfg.crop)
- p->fimg = image_util::crop(*m, cfg.contrast_threshold, cfg.max_cropping);
- else
- p->fimg = *m;
- if (cfg.blur_window > 1)
- cv::blur(p->fimg, p->fimg, cv::Size(cfg.blur_window, cfg.blur_window));
- p->get_light_charistics();
- p->get_light_variance();
- p->get_signature();
- p->fimg.release();
- p->lch.release();
- p->lv.clear();
- return signature(p);
-}
-
-signature signature::from_cvmatrix(cv::Mat *m, const signature_config &cfg)
-{
- cv::Mat ma, bw;
- double sc = 1;
- switch (m->depth())
- {
- case CV_8U: sc = 1. / 255; break;
- case CV_16U: sc = 1. / 65535; break;
- }
- m->convertTo(ma, CV_32F, sc);
- if (m->channels() == 4)
- ma = image_util::blend_white(ma);
- if (ma.channels() == 3)
- cv::cvtColor(ma, bw, cv::COLOR_RGB2GRAY);
- else
- bw = ma;
- return signature::from_preprocessed_matrix(&bw, cfg);
-}
-
-signature signature::from_file(const char *fn, const signature_config &cfg)
-{
- cv::Mat img = cv::imread(fn, cv::IMREAD_UNCHANGED);
- return signature::from_cvmatrix(&img, cfg);
-}
-
-signature signature::from_path(const std::filesystem::path &path, const signature_config &cfg)
-{
- cv::Mat img = image_util::imread_path(path, cv::IMREAD_UNCHANGED);
- return signature::from_cvmatrix(&img, cfg);
-}
-
-signature_config signature::default_cfg()
-{
- return _default_cfg;
-}
-
-size_t signature_hash::operator()(signature const& sig) const noexcept
-{
- if (sig.p->compressed)
- return compressed_vector_hash<uint8_t, 3>{}(sig.p->ct);
- else
- {
- size_t ret = 0;
- for (uint8_t &v : sig.p->uct)
- ret ^= v + 0x9e3779b9 + (ret << 6) + (ret >> 2);
- return ret;
- }
-}