1 /*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "phash_fingerprinter.h"
18
19 #include "array2d.h"
20 #include "fast_dct-inl.h"
21 #include "fast_dct.h"
22 #include "phash_config.h"
23
24 namespace android {
25
26 constexpr int kResizedLength = 8;
27
GenerateFingerprint(const uint8_t * frame)28 int64_t PhashFingerprinter::GenerateFingerprint(const uint8_t* frame) {
29 // 1. verify input
30 if (frame == nullptr) {
31 return 0;
32 }
33
34 // 2. Compute the DCT
35 Array2D<const uint8_t> dct_in(frame);
36 Array2D<int16_t> dct_out(dct_buf_);
37
38 FastDCT<const uint8_t, int16_t> dct(kImageLength);
39 dct.ForwardTransform2D(dct_in, &dct_out);
40
41 // 3. Simplify the DCT by only using the coefficients in the top-left 8x8
42 // window (i.e. those for the lowest frequencies).
43 double total = 0;
44 for (int x = 0; x < kResizedLength; x++) {
45 for (int y = 0; y < kResizedLength; y++) {
46 total += dct_out(x, y);
47 }
48 }
49 // Remove the DC component at (0, 0) from total.
50 total -= dct_out(0, 0);
51
52 // 4. Compute the average
53 double average = total / ((kResizedLength * kResizedLength) - 1);
54
55 // 5. Further simplify the DCT by setting each value to 0 or 1 based on
56 // whether the DCT value is larger than the average, then store each value as
57 // a bit in an int64.
58 int64_t fingerprint = 0;
59 for (int x = 0; x < kResizedLength; x++) {
60 for (int y = 0; y < kResizedLength; y++) {
61 fingerprint <<= 1;
62 fingerprint |= (dct_out(x, y) > average ? 1 : 0);
63 }
64 }
65 // Remove the DC component at (0, 0)
66 fingerprint &= ~(1ULL << 63);
67
68 return fingerprint;
69 }
70
71 } // namespace android
72