aboutsummaryrefslogtreecommitdiff
path: root/imageutil.cpp
blob: 3fd8a94f12e1741ee5b2f43d3ada4b05a219b0ea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//Chris Xiong 2022
//License: MPL-2.0
#include <algorithm>
#include <cmath>
#include <fstream>
#include <iterator>
#include <limits>
//#include <cstdio>

#include <opencv2/imgcodecs.hpp>

#include "imageutil.hpp"

//libpuzzle uses a contrast-based cropping, and clamps the cropped area to a given percentage.
cv::Range image_util::crop_axis(cv::InputArray s, int axis, double contrast_threshold, double max_crop_ratio)
{
    //axis: 0=x (returns range of columns), 1=y (returns range of rows)
    //input matrix must be continuous
    cv::Mat m = s.getMat();
    cv::Size sz = m.size();
    if (axis == 0)
        sz = cv::Size(m.rows, m.cols);
    int innerstride = axis == 0 ? m.cols : 1;
    int outerstride = axis == 0 ? 1 - m.cols * m.rows : 0;
    std::vector<double> contrs;
    const float *data = m.ptr<float>(0);
    const float *dp = data;
    double total_contr = 0.;
    for (int i = 0; i < sz.height; ++i)
    {
        double accum = 0.;
        float lastv = *data;
        for (int j = 0 ; j < sz.width; ++j)
        {
            data += innerstride;
            //printf("%d %d\n", (data - dp) / m.cols, (data - dp) % m.cols);
            if (data - dp >= sz.height * sz.width)
                break;
            accum += fabsf(*data - lastv);
            lastv = *data;
        }
        //printf("---\n");
        data += outerstride;
        contrs.push_back(accum);
        total_contr += accum;
    }
    //printf("======\n");
    //for (size_t i = 0; i < contrs.size(); ++i) printf("%.4f ",contrs[i]/total_contr);
    //printf("\n%f====\n",total_contr);
    double realth = total_contr * contrast_threshold;
    int l = 0, r = sz.height - 1;
    total_contr = 0;
    for (; l < sz.height; ++l)
    {
        total_contr += contrs[l];
        if (total_contr >= realth) break;
    }
    total_contr = 0;
    for (; r > 0; --r)
    {
        total_contr += contrs[r];
        if (total_contr >= realth) break;
    }
    int crop_max = (int)round(sz.height * max_crop_ratio);
    return cv::Range(std::min(l, crop_max), std::max(r, sz.height - 1 - crop_max) + 1);
}

cv::Mat image_util::crop(cv::InputArray s, double contrast_threshold, double max_crop_ratio)
{
    //input matrix must be continuous
    cv::Range xr = crop_axis(s, 0, contrast_threshold, max_crop_ratio);
    cv::Range yr = crop_axis(s, 1, contrast_threshold, max_crop_ratio);
    //printf("%d,%d %d,%d\n",yr.start,yr.end,xr.start,xr.end);
    return s.getMat()(yr, xr);
}

double image_util::median(std::vector<double> &v)
{
    if (v.empty())
        return std::numeric_limits<double>::quiet_NaN();
    if (v.size() % 2)
    {
        int m = v.size() / 2;
        std::vector<double>::iterator mt = v.begin() + m;
        std::nth_element(v.begin(), mt, v.end());
        return *mt;
    }
    else
    {
        int m = v.size() / 2;
        int n = m - 1;
        std::vector<double>::iterator mt, nt;
        mt = v.begin() + m;
        nt = v.begin() + n;
        std::nth_element(v.begin(), mt, v.end());
        std::nth_element(v.begin(), nt, v.end());
        return (*mt + *nt) / 2.;
    }
}

cv::Mat image_util::blend_white(cv::Mat m)
{
    //input must be a continuous, CV_32FC4 matrix
    cv::Mat ret;
    ret.create(m.size(), CV_32FC3);
    size_t p = m.size().width * m.size().height;
    float *d = m.ptr<float>(0);
    float *o = ret.ptr<float>(0);
    for (size_t i = 0; i < p; ++i)
    {
        float a = d[3];
        o[0] = d[0] * a + (1. - a);
        o[1] = d[1] * a + (1. - a);
        o[2] = d[2] * a + (1. - a);
        d += 4;
        o += 3;
    }
    return ret;
}

cv::Mat image_util::imread_path(const std::filesystem::path &p, int flags)
{
    auto size = std::filesystem::file_size(p);
    std::fstream fst(p, std::ios::binary | std::ios::in);
    std::vector<char> dat;
    dat.resize(size);
    fst.read(dat.data(), size);
    fst.close();
    cv::Mat img = cv::imdecode(dat, flags);
    return img;
}