mirror of
https://github.com/opencv/opencv.git
synced 2026-07-22 03:43:03 +04:00
Compare commits
269 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64e6cf9fe5 | |||
| ed788229ed | |||
| 9564aa1fdb | |||
| 24b05cb308 | |||
| dff8e29f98 | |||
| 4733a19bab | |||
| 5bf7345743 | |||
| 4342657762 | |||
| e801f0e954 | |||
| 9cd1d087c3 | |||
| 8d22ac200f | |||
| 28a5f7d66b | |||
| a8345133ac | |||
| f5a84f75c4 | |||
| aa80f754f4 | |||
| 5d15c65e48 | |||
| f8b16fa293 | |||
| af04b422c9 | |||
| c97ff6c0f9 | |||
| 971ae00942 | |||
| 21ee54c3d1 | |||
| 90a17cf964 | |||
| 60ba6ef916 | |||
| 424e1150ae | |||
| d1c35e7b61 | |||
| 3d60a9b96c | |||
| 60f81032bb | |||
| a45928045a | |||
| f62241b780 | |||
| 43302c79ca | |||
| 94f73ee680 | |||
| ff4d3d27dd | |||
| 682653c6f8 | |||
| e6ce752da1 | |||
| 1c4a64f0a1 | |||
| afa072578c | |||
| 5ee7abbe3c | |||
| f2cce5fd8c | |||
| 7d61426279 | |||
| 8b97c93f3d | |||
| 2a11103a73 | |||
| 15612ebd39 | |||
| d1bb2055da | |||
| 416848066c | |||
| 76b5e19eb3 | |||
| a675c4937a | |||
| 6ea29a7696 | |||
| b89581960c | |||
| 4ec4ec844f | |||
| e47f3e5bcc | |||
| 9a27901edc | |||
| 7b298b0995 | |||
| 435c97c7a2 | |||
| 939099b9ce | |||
| 2a19db0f0a | |||
| fe77223dee | |||
| 45f6931352 | |||
| b9435b9e38 | |||
| a2642d83d3 | |||
| a4cb914656 | |||
| 2817cbe450 | |||
| c2ca3ee2fa | |||
| 13bc55a015 | |||
| 766465ce94 | |||
| a011035ed6 | |||
| 734de34b7a | |||
| 883c4c60c3 | |||
| b1b505f783 | |||
| 816f82682b | |||
| 629d47fcd8 | |||
| beb5b291b9 | |||
| 51d54ad4f0 | |||
| fb5db23463 | |||
| 0a35b97e75 | |||
| eea517be92 | |||
| b369c456f2 | |||
| 660a709840 | |||
| d99d18304a | |||
| 76a27e3399 | |||
| 134094a442 | |||
| c790779a37 | |||
| 72f35e0626 | |||
| f21bde4d9f | |||
| 986c5084a4 | |||
| 38180c2c97 | |||
| 95e36fd488 | |||
| 36c9f7c3df | |||
| d8e10f3a8d | |||
| 4dfa0a0383 | |||
| 818585fd12 | |||
| eb44e0a556 | |||
| ca1ba7a53d | |||
| 7523c777c5 | |||
| 43d58aa760 | |||
| 20ac7f40f6 | |||
| 8a18d132fc | |||
| 9a4404276a | |||
| f5b9705c70 | |||
| 101a147496 | |||
| 8d74101f07 | |||
| 41af8aa046 | |||
| 0dfab6bbd0 | |||
| 873250f5de | |||
| 6c37e10c83 | |||
| 70146700aa | |||
| 5af747c6fd | |||
| 17dfae77af | |||
| af997529a1 | |||
| 5639f5a296 | |||
| 0c644d1ec8 | |||
| a093a0e05c | |||
| cdc469786c | |||
| 5ff1fababc | |||
| 6276b86a78 | |||
| 6e14cc2189 | |||
| 9e906d9e21 | |||
| dc4af58be0 | |||
| 4a3ab8fbdb | |||
| b38547ee9a | |||
| 501ff7f056 | |||
| 373160ce00 | |||
| 50ac880335 | |||
| 54e6f5c237 | |||
| 3266ac7667 | |||
| ca28274895 | |||
| ec55b6f6db | |||
| 16ad53f354 | |||
| 86042af108 | |||
| e459a5108c | |||
| a2aa8db5a9 | |||
| 75315fb297 | |||
| c40fbad12e | |||
| 5d96f984b1 | |||
| 9d14c0b37a | |||
| 2f636b4456 | |||
| e07a488012 | |||
| 77bf5593e5 | |||
| 26513285dd | |||
| de64db3064 | |||
| ec8db970f9 | |||
| 09d54c9f52 | |||
| d00eb451bf | |||
| 3f431a16a3 | |||
| 593e240d7c | |||
| fb9d59ab15 | |||
| aff8c9bd28 | |||
| 2185bce4b7 | |||
| f4d55d512f | |||
| 955b20230c | |||
| 686ea5c1a6 | |||
| 7ec91aefc1 | |||
| 973b367da6 | |||
| 1d33335e33 | |||
| 1f57eb93fd | |||
| 6773b938b3 | |||
| ac4fd4f4ae | |||
| 94f1c3d152 | |||
| ad8d7e84b9 | |||
| b48959fa57 | |||
| 3cdbcc1645 | |||
| 763b80d5fa | |||
| d0c767428b | |||
| a67248f386 | |||
| c638f085aa | |||
| 7ecdcf6ca6 | |||
| af92a517a7 | |||
| ba58bba4e8 | |||
| e0b5637474 | |||
| d32d31577c | |||
| e9dcecf9b4 | |||
| fccf284088 | |||
| cfc781949d | |||
| 3755099bd4 | |||
| af23375352 | |||
| 6053996253 | |||
| dd9262c318 | |||
| 35cebbd167 | |||
| d66aa2e0ff | |||
| 7c4158d8c2 | |||
| c546a27de7 | |||
| 377fcc062d | |||
| 07ef08e966 | |||
| 2e20f06f8e | |||
| 54d9597522 | |||
| f3e788b8ab | |||
| cdbfdcc363 | |||
| 2112aa31e6 | |||
| 2c2716de0f | |||
| 6d5b900324 | |||
| 53139e6ebe | |||
| a893969ec9 | |||
| d5bbb16066 | |||
| 21c38bbdaf | |||
| b7c8e9e874 | |||
| e65b51ca3c | |||
| d56535afce | |||
| 4e156a162f | |||
| ed7e4273cd | |||
| 657c17bb8c | |||
| cec7cc037b | |||
| 5c12bafe80 | |||
| d2e02779c4 | |||
| c2f2ea6b85 | |||
| af433d0352 | |||
| ee044771a7 | |||
| edc5518f68 | |||
| 79f792ad05 | |||
| a9d23a6479 | |||
| bad4e5c3eb | |||
| e86c888a92 | |||
| a71ff50130 | |||
| 80c4cedd25 | |||
| 732657cc46 | |||
| 86a8ff6129 | |||
| d8ab83600b | |||
| 6ec5ae0215 | |||
| 7cf1054d36 | |||
| 42b1d04999 | |||
| eabe679f78 | |||
| 1ce5a724c7 | |||
| d65fead337 | |||
| 17e2bf5717 | |||
| 5e8d8df847 | |||
| c46f119e0e | |||
| 1accf3b3f4 | |||
| 5a6a49405d | |||
| 1864b64f64 | |||
| 4bd2ad30c4 | |||
| 6e9eca29e2 | |||
| dfe0368835 | |||
| a8d14e88fe | |||
| 6576e8b927 | |||
| acb3b3bd4d | |||
| af61a15839 | |||
| 3ada597449 | |||
| 938d8dce06 | |||
| 6e85e852d4 | |||
| 70a5553499 | |||
| 90af2835a2 | |||
| 83e2e124a3 | |||
| adbd613660 | |||
| 849d8d31fe | |||
| 24ebca5c59 | |||
| ead7d6d80f | |||
| 34df28db2b | |||
| a2b3cd9a2c | |||
| d31da08d43 | |||
| 17e9fde75a | |||
| 692e1eccb6 | |||
| 009f5f74ef | |||
| 4c7db02925 | |||
| c4e2e17b0c | |||
| 9255df44d0 | |||
| 0e40c8a031 | |||
| 86e7d82418 | |||
| 3b070517ad | |||
| ad5d14ec0e | |||
| bce653117f | |||
| ad172726c0 | |||
| b1a8de0901 | |||
| 823884b064 | |||
| 6a7d1c15d3 | |||
| d154fa4b4c | |||
| 47fc889df0 | |||
| 027769bf5d | |||
| 9ca9249992 | |||
| ec91a3d59d | |||
| dd4f591d54 | |||
| 0a1b957331 |
@@ -22,3 +22,4 @@ bin/
|
||||
*.log
|
||||
*.tlog
|
||||
build
|
||||
node_modules
|
||||
|
||||
Vendored
+5
-5
@@ -1,8 +1,8 @@
|
||||
# Binaries branch name: ffmpeg/3.4_20190905
|
||||
# Binaries were created for OpenCV: fafada28ebc0f2e5423a7d8ece425574ef01ff60
|
||||
ocv_update(FFMPEG_BINARIES_COMMIT "bf1730f4c4ba1996bed1fe268b52e4e942151cd6")
|
||||
ocv_update(FFMPEG_FILE_HASH_BIN32 "6899624f88cb4cbb1604edc5e12b18ab")
|
||||
ocv_update(FFMPEG_FILE_HASH_BIN64 "4729c052cb0c53ab56e9a0eed91559df")
|
||||
# Binaries branch name: ffmpeg/3.4_20191118
|
||||
# Binaries were created for OpenCV: 3f431a16a38be35e52b4887a3591d23030d34fc5
|
||||
ocv_update(FFMPEG_BINARIES_COMMIT "548e3c997a80d65f710b9048f1d33371e3a203ac")
|
||||
ocv_update(FFMPEG_FILE_HASH_BIN32 "168635a192fc2d2ae7d7d40150f0b349")
|
||||
ocv_update(FFMPEG_FILE_HASH_BIN64 "cbc25f8f2954475b127c7558558c18e6")
|
||||
ocv_update(FFMPEG_FILE_HASH_CMAKE "3b90f67f4b429e77d3da36698cef700c")
|
||||
|
||||
function(download_win_ffmpeg script_var)
|
||||
|
||||
Vendored
+11
-6
@@ -61,12 +61,17 @@ static const uint16_t kAcTable[128] = {
|
||||
|
||||
void VP8ParseQuant(VP8Decoder* const dec) {
|
||||
VP8BitReader* const br = &dec->br_;
|
||||
const int base_q0 = VP8GetValue(br, 7);
|
||||
const int dqy1_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
|
||||
const int dqy2_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
|
||||
const int dqy2_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
|
||||
const int dquv_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
|
||||
const int dquv_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
|
||||
const int base_q0 = VP8GetValue(br, 7, "global-header");
|
||||
const int dqy1_dc = VP8Get(br, "global-header") ?
|
||||
VP8GetSignedValue(br, 4, "global-header") : 0;
|
||||
const int dqy2_dc = VP8Get(br, "global-header") ?
|
||||
VP8GetSignedValue(br, 4, "global-header") : 0;
|
||||
const int dqy2_ac = VP8Get(br, "global-header") ?
|
||||
VP8GetSignedValue(br, 4, "global-header") : 0;
|
||||
const int dquv_dc = VP8Get(br, "global-header") ?
|
||||
VP8GetSignedValue(br, 4, "global-header") : 0;
|
||||
const int dquv_ac = VP8Get(br, "global-header") ?
|
||||
VP8GetSignedValue(br, 4, "global-header") : 0;
|
||||
|
||||
const VP8SegmentHeader* const hdr = &dec->segment_hdr_;
|
||||
int i;
|
||||
|
||||
Vendored
+31
-26
@@ -296,20 +296,21 @@ static void ParseIntraMode(VP8BitReader* const br,
|
||||
// to decode more than 1 keyframe.
|
||||
if (dec->segment_hdr_.update_map_) {
|
||||
// Hardcoded tree parsing
|
||||
block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0])
|
||||
? VP8GetBit(br, dec->proba_.segments_[1])
|
||||
: 2 + VP8GetBit(br, dec->proba_.segments_[2]);
|
||||
block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0], "segments")
|
||||
? VP8GetBit(br, dec->proba_.segments_[1], "segments")
|
||||
: VP8GetBit(br, dec->proba_.segments_[2], "segments") + 2;
|
||||
} else {
|
||||
block->segment_ = 0; // default for intra
|
||||
}
|
||||
if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_);
|
||||
if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_, "skip");
|
||||
|
||||
block->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first
|
||||
block->is_i4x4_ = !VP8GetBit(br, 145, "block-size");
|
||||
if (!block->is_i4x4_) {
|
||||
// Hardcoded 16x16 intra-mode decision tree.
|
||||
const int ymode =
|
||||
VP8GetBit(br, 156) ? (VP8GetBit(br, 128) ? TM_PRED : H_PRED)
|
||||
: (VP8GetBit(br, 163) ? V_PRED : DC_PRED);
|
||||
VP8GetBit(br, 156, "pred-modes") ?
|
||||
(VP8GetBit(br, 128, "pred-modes") ? TM_PRED : H_PRED) :
|
||||
(VP8GetBit(br, 163, "pred-modes") ? V_PRED : DC_PRED);
|
||||
block->imodes_[0] = ymode;
|
||||
memset(top, ymode, 4 * sizeof(*top));
|
||||
memset(left, ymode, 4 * sizeof(*left));
|
||||
@@ -323,22 +324,25 @@ static void ParseIntraMode(VP8BitReader* const br,
|
||||
const uint8_t* const prob = kBModesProba[top[x]][ymode];
|
||||
#if (USE_GENERIC_TREE == 1)
|
||||
// Generic tree-parsing
|
||||
int i = kYModesIntra4[VP8GetBit(br, prob[0])];
|
||||
int i = kYModesIntra4[VP8GetBit(br, prob[0], "pred-modes")];
|
||||
while (i > 0) {
|
||||
i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i])];
|
||||
i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i], "pred-modes")];
|
||||
}
|
||||
ymode = -i;
|
||||
#else
|
||||
// Hardcoded tree parsing
|
||||
ymode = !VP8GetBit(br, prob[0]) ? B_DC_PRED :
|
||||
!VP8GetBit(br, prob[1]) ? B_TM_PRED :
|
||||
!VP8GetBit(br, prob[2]) ? B_VE_PRED :
|
||||
!VP8GetBit(br, prob[3]) ?
|
||||
(!VP8GetBit(br, prob[4]) ? B_HE_PRED :
|
||||
(!VP8GetBit(br, prob[5]) ? B_RD_PRED : B_VR_PRED)) :
|
||||
(!VP8GetBit(br, prob[6]) ? B_LD_PRED :
|
||||
(!VP8GetBit(br, prob[7]) ? B_VL_PRED :
|
||||
(!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
|
||||
ymode = !VP8GetBit(br, prob[0], "pred-modes") ? B_DC_PRED :
|
||||
!VP8GetBit(br, prob[1], "pred-modes") ? B_TM_PRED :
|
||||
!VP8GetBit(br, prob[2], "pred-modes") ? B_VE_PRED :
|
||||
!VP8GetBit(br, prob[3], "pred-modes") ?
|
||||
(!VP8GetBit(br, prob[4], "pred-modes") ? B_HE_PRED :
|
||||
(!VP8GetBit(br, prob[5], "pred-modes") ? B_RD_PRED
|
||||
: B_VR_PRED)) :
|
||||
(!VP8GetBit(br, prob[6], "pred-modes") ? B_LD_PRED :
|
||||
(!VP8GetBit(br, prob[7], "pred-modes") ? B_VL_PRED :
|
||||
(!VP8GetBit(br, prob[8], "pred-modes") ? B_HD_PRED
|
||||
: B_HU_PRED))
|
||||
);
|
||||
#endif // USE_GENERIC_TREE
|
||||
top[x] = ymode;
|
||||
}
|
||||
@@ -348,9 +352,9 @@ static void ParseIntraMode(VP8BitReader* const br,
|
||||
}
|
||||
}
|
||||
// Hardcoded UVMode decision tree
|
||||
block->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED
|
||||
: !VP8GetBit(br, 114) ? V_PRED
|
||||
: VP8GetBit(br, 183) ? TM_PRED : H_PRED;
|
||||
block->uvmode_ = !VP8GetBit(br, 142, "pred-modes-uv") ? DC_PRED
|
||||
: !VP8GetBit(br, 114, "pred-modes-uv") ? V_PRED
|
||||
: VP8GetBit(br, 183, "pred-modes-uv") ? TM_PRED : H_PRED;
|
||||
}
|
||||
|
||||
int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) {
|
||||
@@ -514,8 +518,10 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
|
||||
for (b = 0; b < NUM_BANDS; ++b) {
|
||||
for (c = 0; c < NUM_CTX; ++c) {
|
||||
for (p = 0; p < NUM_PROBAS; ++p) {
|
||||
const int v = VP8GetBit(br, CoeffsUpdateProba[t][b][c][p]) ?
|
||||
VP8GetValue(br, 8) : CoeffsProba0[t][b][c][p];
|
||||
const int v =
|
||||
VP8GetBit(br, CoeffsUpdateProba[t][b][c][p], "global-header") ?
|
||||
VP8GetValue(br, 8, "global-header") :
|
||||
CoeffsProba0[t][b][c][p];
|
||||
proba->bands_[t][b].probas_[c][p] = v;
|
||||
}
|
||||
}
|
||||
@@ -524,9 +530,8 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
|
||||
proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]];
|
||||
}
|
||||
}
|
||||
dec->use_skip_proba_ = VP8Get(br);
|
||||
dec->use_skip_proba_ = VP8Get(br, "global-header");
|
||||
if (dec->use_skip_proba_) {
|
||||
dec->skip_p_ = VP8GetValue(br, 8);
|
||||
dec->skip_p_ = VP8GetValue(br, 8, "global-header");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+42
-39
@@ -161,23 +161,26 @@ static int ParseSegmentHeader(VP8BitReader* br,
|
||||
VP8SegmentHeader* hdr, VP8Proba* proba) {
|
||||
assert(br != NULL);
|
||||
assert(hdr != NULL);
|
||||
hdr->use_segment_ = VP8Get(br);
|
||||
hdr->use_segment_ = VP8Get(br, "global-header");
|
||||
if (hdr->use_segment_) {
|
||||
hdr->update_map_ = VP8Get(br);
|
||||
if (VP8Get(br)) { // update data
|
||||
hdr->update_map_ = VP8Get(br, "global-header");
|
||||
if (VP8Get(br, "global-header")) { // update data
|
||||
int s;
|
||||
hdr->absolute_delta_ = VP8Get(br);
|
||||
hdr->absolute_delta_ = VP8Get(br, "global-header");
|
||||
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
||||
hdr->quantizer_[s] = VP8Get(br) ? VP8GetSignedValue(br, 7) : 0;
|
||||
hdr->quantizer_[s] = VP8Get(br, "global-header") ?
|
||||
VP8GetSignedValue(br, 7, "global-header") : 0;
|
||||
}
|
||||
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
||||
hdr->filter_strength_[s] = VP8Get(br) ? VP8GetSignedValue(br, 6) : 0;
|
||||
hdr->filter_strength_[s] = VP8Get(br, "global-header") ?
|
||||
VP8GetSignedValue(br, 6, "global-header") : 0;
|
||||
}
|
||||
}
|
||||
if (hdr->update_map_) {
|
||||
int s;
|
||||
for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
|
||||
proba->segments_[s] = VP8Get(br) ? VP8GetValue(br, 8) : 255u;
|
||||
proba->segments_[s] = VP8Get(br, "global-header") ?
|
||||
VP8GetValue(br, 8, "global-header") : 255u;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -205,7 +208,7 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
|
||||
size_t last_part;
|
||||
size_t p;
|
||||
|
||||
dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2)) - 1;
|
||||
dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2, "global-header")) - 1;
|
||||
last_part = dec->num_parts_minus_one_;
|
||||
if (size < 3 * last_part) {
|
||||
// we can't even read the sizes with sz[]! That's a failure.
|
||||
@@ -229,21 +232,21 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
|
||||
// Paragraph 9.4
|
||||
static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
|
||||
VP8FilterHeader* const hdr = &dec->filter_hdr_;
|
||||
hdr->simple_ = VP8Get(br);
|
||||
hdr->level_ = VP8GetValue(br, 6);
|
||||
hdr->sharpness_ = VP8GetValue(br, 3);
|
||||
hdr->use_lf_delta_ = VP8Get(br);
|
||||
hdr->simple_ = VP8Get(br, "global-header");
|
||||
hdr->level_ = VP8GetValue(br, 6, "global-header");
|
||||
hdr->sharpness_ = VP8GetValue(br, 3, "global-header");
|
||||
hdr->use_lf_delta_ = VP8Get(br, "global-header");
|
||||
if (hdr->use_lf_delta_) {
|
||||
if (VP8Get(br)) { // update lf-delta?
|
||||
if (VP8Get(br, "global-header")) { // update lf-delta?
|
||||
int i;
|
||||
for (i = 0; i < NUM_REF_LF_DELTAS; ++i) {
|
||||
if (VP8Get(br)) {
|
||||
hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6);
|
||||
if (VP8Get(br, "global-header")) {
|
||||
hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header");
|
||||
}
|
||||
}
|
||||
for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
|
||||
if (VP8Get(br)) {
|
||||
hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6);
|
||||
if (VP8Get(br, "global-header")) {
|
||||
hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,8 +355,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
||||
buf_size -= frm_hdr->partition_length_;
|
||||
|
||||
if (frm_hdr->key_frame_) {
|
||||
pic_hdr->colorspace_ = VP8Get(br);
|
||||
pic_hdr->clamp_type_ = VP8Get(br);
|
||||
pic_hdr->colorspace_ = VP8Get(br, "global-header");
|
||||
pic_hdr->clamp_type_ = VP8Get(br, "global-header");
|
||||
}
|
||||
if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) {
|
||||
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||
@@ -378,7 +381,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
||||
"Not a key frame.");
|
||||
}
|
||||
|
||||
VP8Get(br); // ignore the value of update_proba_
|
||||
VP8Get(br, "global-header"); // ignore the value of update_proba_
|
||||
|
||||
VP8ParseProba(br, dec);
|
||||
|
||||
@@ -403,28 +406,28 @@ static const uint8_t kZigzag[16] = {
|
||||
// See section 13-2: http://tools.ietf.org/html/rfc6386#section-13.2
|
||||
static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
|
||||
int v;
|
||||
if (!VP8GetBit(br, p[3])) {
|
||||
if (!VP8GetBit(br, p[4])) {
|
||||
if (!VP8GetBit(br, p[3], "coeffs")) {
|
||||
if (!VP8GetBit(br, p[4], "coeffs")) {
|
||||
v = 2;
|
||||
} else {
|
||||
v = 3 + VP8GetBit(br, p[5]);
|
||||
v = 3 + VP8GetBit(br, p[5], "coeffs");
|
||||
}
|
||||
} else {
|
||||
if (!VP8GetBit(br, p[6])) {
|
||||
if (!VP8GetBit(br, p[7])) {
|
||||
v = 5 + VP8GetBit(br, 159);
|
||||
if (!VP8GetBit(br, p[6], "coeffs")) {
|
||||
if (!VP8GetBit(br, p[7], "coeffs")) {
|
||||
v = 5 + VP8GetBit(br, 159, "coeffs");
|
||||
} else {
|
||||
v = 7 + 2 * VP8GetBit(br, 165);
|
||||
v += VP8GetBit(br, 145);
|
||||
v = 7 + 2 * VP8GetBit(br, 165, "coeffs");
|
||||
v += VP8GetBit(br, 145, "coeffs");
|
||||
}
|
||||
} else {
|
||||
const uint8_t* tab;
|
||||
const int bit1 = VP8GetBit(br, p[8]);
|
||||
const int bit0 = VP8GetBit(br, p[9 + bit1]);
|
||||
const int bit1 = VP8GetBit(br, p[8], "coeffs");
|
||||
const int bit0 = VP8GetBit(br, p[9 + bit1], "coeffs");
|
||||
const int cat = 2 * bit1 + bit0;
|
||||
v = 0;
|
||||
for (tab = kCat3456[cat]; *tab; ++tab) {
|
||||
v += v + VP8GetBit(br, *tab);
|
||||
v += v + VP8GetBit(br, *tab, "coeffs");
|
||||
}
|
||||
v += 3 + (8 << cat);
|
||||
}
|
||||
@@ -438,24 +441,24 @@ static int GetCoeffsFast(VP8BitReader* const br,
|
||||
int ctx, const quant_t dq, int n, int16_t* out) {
|
||||
const uint8_t* p = prob[n]->probas_[ctx];
|
||||
for (; n < 16; ++n) {
|
||||
if (!VP8GetBit(br, p[0])) {
|
||||
if (!VP8GetBit(br, p[0], "coeffs")) {
|
||||
return n; // previous coeff was last non-zero coeff
|
||||
}
|
||||
while (!VP8GetBit(br, p[1])) { // sequence of zero coeffs
|
||||
while (!VP8GetBit(br, p[1], "coeffs")) { // sequence of zero coeffs
|
||||
p = prob[++n]->probas_[0];
|
||||
if (n == 16) return 16;
|
||||
}
|
||||
{ // non zero coeff
|
||||
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
|
||||
int v;
|
||||
if (!VP8GetBit(br, p[2])) {
|
||||
if (!VP8GetBit(br, p[2], "coeffs")) {
|
||||
v = 1;
|
||||
p = p_ctx[1];
|
||||
} else {
|
||||
v = GetLargeValue(br, p);
|
||||
p = p_ctx[2];
|
||||
}
|
||||
out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0];
|
||||
out[kZigzag[n]] = VP8GetSigned(br, v, "coeffs") * dq[n > 0];
|
||||
}
|
||||
}
|
||||
return 16;
|
||||
@@ -468,24 +471,24 @@ static int GetCoeffsAlt(VP8BitReader* const br,
|
||||
int ctx, const quant_t dq, int n, int16_t* out) {
|
||||
const uint8_t* p = prob[n]->probas_[ctx];
|
||||
for (; n < 16; ++n) {
|
||||
if (!VP8GetBitAlt(br, p[0])) {
|
||||
if (!VP8GetBitAlt(br, p[0], "coeffs")) {
|
||||
return n; // previous coeff was last non-zero coeff
|
||||
}
|
||||
while (!VP8GetBitAlt(br, p[1])) { // sequence of zero coeffs
|
||||
while (!VP8GetBitAlt(br, p[1], "coeffs")) { // sequence of zero coeffs
|
||||
p = prob[++n]->probas_[0];
|
||||
if (n == 16) return 16;
|
||||
}
|
||||
{ // non zero coeff
|
||||
const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
|
||||
int v;
|
||||
if (!VP8GetBitAlt(br, p[2])) {
|
||||
if (!VP8GetBitAlt(br, p[2], "coeffs")) {
|
||||
v = 1;
|
||||
p = p_ctx[1];
|
||||
} else {
|
||||
v = GetLargeValue(br, p);
|
||||
p = p_ctx[2];
|
||||
}
|
||||
out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0];
|
||||
out[kZigzag[n]] = VP8GetSigned(br, v, "coeffs") * dq[n > 0];
|
||||
}
|
||||
}
|
||||
return 16;
|
||||
|
||||
Vendored
+1
-1
@@ -32,7 +32,7 @@ extern "C" {
|
||||
// version numbers
|
||||
#define DEC_MAJ_VERSION 1
|
||||
#define DEC_MIN_VERSION 0
|
||||
#define DEC_REV_VERSION 2
|
||||
#define DEC_REV_VERSION 3
|
||||
|
||||
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
||||
// Constraints are: We need to store one 16x16 block of luma samples (y),
|
||||
|
||||
Vendored
+61
-64
@@ -362,12 +362,8 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
VP8LMetadata* const hdr = &dec->hdr_;
|
||||
uint32_t* huffman_image = NULL;
|
||||
HTreeGroup* htree_groups = NULL;
|
||||
// When reading htrees, some might be unused, as the format allows it.
|
||||
// We will still read them but put them in this htree_group_bogus.
|
||||
HTreeGroup htree_group_bogus;
|
||||
HuffmanCode* huffman_tables = NULL;
|
||||
HuffmanCode* huffman_tables_bogus = NULL;
|
||||
HuffmanCode* next = NULL;
|
||||
HuffmanCode* huffman_table = NULL;
|
||||
int num_htree_groups = 1;
|
||||
int num_htree_groups_max = 1;
|
||||
int max_alphabet_size = 0;
|
||||
@@ -418,12 +414,6 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
if (*mapped_group == -1) *mapped_group = num_htree_groups++;
|
||||
huffman_image[i] = *mapped_group;
|
||||
}
|
||||
huffman_tables_bogus = (HuffmanCode*)WebPSafeMalloc(
|
||||
table_size, sizeof(*huffman_tables_bogus));
|
||||
if (huffman_tables_bogus == NULL) {
|
||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
} else {
|
||||
num_htree_groups = num_htree_groups_max;
|
||||
}
|
||||
@@ -453,63 +443,71 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
goto Error;
|
||||
}
|
||||
|
||||
next = huffman_tables;
|
||||
huffman_table = huffman_tables;
|
||||
for (i = 0; i < num_htree_groups_max; ++i) {
|
||||
// If the index "i" is unused in the Huffman image, read the coefficients
|
||||
// but store them to a bogus htree_group.
|
||||
const int is_bogus = (mapping != NULL && mapping[i] == -1);
|
||||
HTreeGroup* const htree_group =
|
||||
is_bogus ? &htree_group_bogus :
|
||||
&htree_groups[(mapping == NULL) ? i : mapping[i]];
|
||||
HuffmanCode** const htrees = htree_group->htrees;
|
||||
HuffmanCode* huffman_tables_i = is_bogus ? huffman_tables_bogus : next;
|
||||
int size;
|
||||
int total_size = 0;
|
||||
int is_trivial_literal = 1;
|
||||
int max_bits = 0;
|
||||
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
||||
int alphabet_size = kAlphabetSize[j];
|
||||
htrees[j] = huffman_tables_i;
|
||||
if (j == 0 && color_cache_bits > 0) {
|
||||
alphabet_size += 1 << color_cache_bits;
|
||||
}
|
||||
size =
|
||||
ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables_i);
|
||||
if (size == 0) {
|
||||
goto Error;
|
||||
}
|
||||
if (is_trivial_literal && kLiteralMap[j] == 1) {
|
||||
is_trivial_literal = (huffman_tables_i->bits == 0);
|
||||
}
|
||||
total_size += huffman_tables_i->bits;
|
||||
huffman_tables_i += size;
|
||||
if (j <= ALPHA) {
|
||||
int local_max_bits = code_lengths[0];
|
||||
int k;
|
||||
for (k = 1; k < alphabet_size; ++k) {
|
||||
if (code_lengths[k] > local_max_bits) {
|
||||
local_max_bits = code_lengths[k];
|
||||
}
|
||||
// If the index "i" is unused in the Huffman image, just make sure the
|
||||
// coefficients are valid but do not store them.
|
||||
if (mapping != NULL && mapping[i] == -1) {
|
||||
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
||||
int alphabet_size = kAlphabetSize[j];
|
||||
if (j == 0 && color_cache_bits > 0) {
|
||||
alphabet_size += (1 << color_cache_bits);
|
||||
}
|
||||
// Passing in NULL so that nothing gets filled.
|
||||
if (!ReadHuffmanCode(alphabet_size, dec, code_lengths, NULL)) {
|
||||
goto Error;
|
||||
}
|
||||
max_bits += local_max_bits;
|
||||
}
|
||||
}
|
||||
if (!is_bogus) next = huffman_tables_i;
|
||||
htree_group->is_trivial_literal = is_trivial_literal;
|
||||
htree_group->is_trivial_code = 0;
|
||||
if (is_trivial_literal) {
|
||||
const int red = htrees[RED][0].value;
|
||||
const int blue = htrees[BLUE][0].value;
|
||||
const int alpha = htrees[ALPHA][0].value;
|
||||
htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
|
||||
if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
|
||||
htree_group->is_trivial_code = 1;
|
||||
htree_group->literal_arb |= htrees[GREEN][0].value << 8;
|
||||
} else {
|
||||
HTreeGroup* const htree_group =
|
||||
&htree_groups[(mapping == NULL) ? i : mapping[i]];
|
||||
HuffmanCode** const htrees = htree_group->htrees;
|
||||
int size;
|
||||
int total_size = 0;
|
||||
int is_trivial_literal = 1;
|
||||
int max_bits = 0;
|
||||
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
||||
int alphabet_size = kAlphabetSize[j];
|
||||
htrees[j] = huffman_table;
|
||||
if (j == 0 && color_cache_bits > 0) {
|
||||
alphabet_size += (1 << color_cache_bits);
|
||||
}
|
||||
size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table);
|
||||
if (size == 0) {
|
||||
goto Error;
|
||||
}
|
||||
if (is_trivial_literal && kLiteralMap[j] == 1) {
|
||||
is_trivial_literal = (huffman_table->bits == 0);
|
||||
}
|
||||
total_size += huffman_table->bits;
|
||||
huffman_table += size;
|
||||
if (j <= ALPHA) {
|
||||
int local_max_bits = code_lengths[0];
|
||||
int k;
|
||||
for (k = 1; k < alphabet_size; ++k) {
|
||||
if (code_lengths[k] > local_max_bits) {
|
||||
local_max_bits = code_lengths[k];
|
||||
}
|
||||
}
|
||||
max_bits += local_max_bits;
|
||||
}
|
||||
}
|
||||
htree_group->is_trivial_literal = is_trivial_literal;
|
||||
htree_group->is_trivial_code = 0;
|
||||
if (is_trivial_literal) {
|
||||
const int red = htrees[RED][0].value;
|
||||
const int blue = htrees[BLUE][0].value;
|
||||
const int alpha = htrees[ALPHA][0].value;
|
||||
htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
|
||||
if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
|
||||
htree_group->is_trivial_code = 1;
|
||||
htree_group->literal_arb |= htrees[GREEN][0].value << 8;
|
||||
}
|
||||
}
|
||||
htree_group->use_packed_table =
|
||||
!htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
|
||||
if (htree_group->use_packed_table) BuildPackedTable(htree_group);
|
||||
}
|
||||
htree_group->use_packed_table =
|
||||
!htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
|
||||
if (htree_group->use_packed_table) BuildPackedTable(htree_group);
|
||||
}
|
||||
ok = 1;
|
||||
|
||||
@@ -521,7 +519,6 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||
|
||||
Error:
|
||||
WebPSafeFree(code_lengths);
|
||||
WebPSafeFree(huffman_tables_bogus);
|
||||
WebPSafeFree(mapping);
|
||||
if (!ok) {
|
||||
WebPSafeFree(huffman_image);
|
||||
|
||||
Vendored
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
#define DMUX_MAJ_VERSION 1
|
||||
#define DMUX_MIN_VERSION 0
|
||||
#define DMUX_REV_VERSION 2
|
||||
#define DMUX_REV_VERSION 3
|
||||
|
||||
typedef struct {
|
||||
size_t start_; // start location of the data
|
||||
|
||||
+2
-2
@@ -214,7 +214,7 @@ static void ApplyAlphaMultiply_SSE2(uint8_t* rgba, int alpha_first,
|
||||
// Alpha detection
|
||||
|
||||
static int HasAlpha8b_SSE2(const uint8_t* src, int length) {
|
||||
const __m128i all_0xff = _mm_set1_epi8(0xff);
|
||||
const __m128i all_0xff = _mm_set1_epi8((char)0xff);
|
||||
int i = 0;
|
||||
for (; i + 16 <= length; i += 16) {
|
||||
const __m128i v = _mm_loadu_si128((const __m128i*)(src + i));
|
||||
@@ -228,7 +228,7 @@ static int HasAlpha8b_SSE2(const uint8_t* src, int length) {
|
||||
|
||||
static int HasAlpha32b_SSE2(const uint8_t* src, int length) {
|
||||
const __m128i alpha_mask = _mm_set1_epi32(0xff);
|
||||
const __m128i all_0xff = _mm_set1_epi8(0xff);
|
||||
const __m128i all_0xff = _mm_set1_epi8((char)0xff);
|
||||
int i = 0;
|
||||
// We don't know if we can access the last 3 bytes after the last alpha
|
||||
// value 'src[4 * length - 4]' (because we don't know if alpha is the first
|
||||
|
||||
Vendored
+2
-2
@@ -173,8 +173,8 @@ static int AndroidCPUInfo(CPUFeature feature) {
|
||||
const AndroidCpuFamily cpu_family = android_getCpuFamily();
|
||||
const uint64_t cpu_features = android_getCpuFeatures();
|
||||
if (feature == kNEON) {
|
||||
return (cpu_family == ANDROID_CPU_FAMILY_ARM &&
|
||||
0 != (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON));
|
||||
return cpu_family == ANDROID_CPU_FAMILY_ARM &&
|
||||
(cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Vendored
+7
-7
@@ -326,7 +326,7 @@ static WEBP_INLINE void Update2Pixels_SSE2(__m128i* const pi, __m128i* const qi,
|
||||
const __m128i a1_lo = _mm_srai_epi16(*a0_lo, 7);
|
||||
const __m128i a1_hi = _mm_srai_epi16(*a0_hi, 7);
|
||||
const __m128i delta = _mm_packs_epi16(a1_lo, a1_hi);
|
||||
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||
const __m128i sign_bit = _mm_set1_epi8((char)0x80);
|
||||
*pi = _mm_adds_epi8(*pi, delta);
|
||||
*qi = _mm_subs_epi8(*qi, delta);
|
||||
FLIP_SIGN_BIT2(*pi, *qi);
|
||||
@@ -338,9 +338,9 @@ static WEBP_INLINE void NeedsFilter_SSE2(const __m128i* const p1,
|
||||
const __m128i* const q0,
|
||||
const __m128i* const q1,
|
||||
int thresh, __m128i* const mask) {
|
||||
const __m128i m_thresh = _mm_set1_epi8(thresh);
|
||||
const __m128i m_thresh = _mm_set1_epi8((char)thresh);
|
||||
const __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
|
||||
const __m128i kFE = _mm_set1_epi8(0xFE);
|
||||
const __m128i kFE = _mm_set1_epi8((char)0xFE);
|
||||
const __m128i t2 = _mm_and_si128(t1, kFE); // set lsb of each byte to zero
|
||||
const __m128i t3 = _mm_srli_epi16(t2, 1); // abs(p1 - q1) / 2
|
||||
|
||||
@@ -360,7 +360,7 @@ static WEBP_INLINE void DoFilter2_SSE2(__m128i* const p1, __m128i* const p0,
|
||||
__m128i* const q0, __m128i* const q1,
|
||||
int thresh) {
|
||||
__m128i a, mask;
|
||||
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||
const __m128i sign_bit = _mm_set1_epi8((char)0x80);
|
||||
// convert p1/q1 to int8_t (for GetBaseDelta_SSE2)
|
||||
const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
|
||||
const __m128i q1s = _mm_xor_si128(*q1, sign_bit);
|
||||
@@ -380,7 +380,7 @@ static WEBP_INLINE void DoFilter4_SSE2(__m128i* const p1, __m128i* const p0,
|
||||
const __m128i* const mask,
|
||||
int hev_thresh) {
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||
const __m128i sign_bit = _mm_set1_epi8((char)0x80);
|
||||
const __m128i k64 = _mm_set1_epi8(64);
|
||||
const __m128i k3 = _mm_set1_epi8(3);
|
||||
const __m128i k4 = _mm_set1_epi8(4);
|
||||
@@ -427,7 +427,7 @@ static WEBP_INLINE void DoFilter6_SSE2(__m128i* const p2, __m128i* const p1,
|
||||
const __m128i* const mask,
|
||||
int hev_thresh) {
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
const __m128i sign_bit = _mm_set1_epi8(0x80);
|
||||
const __m128i sign_bit = _mm_set1_epi8((char)0x80);
|
||||
__m128i a, not_hev;
|
||||
|
||||
// compute hev mask
|
||||
@@ -941,7 +941,7 @@ static void VR4_SSE2(uint8_t* dst) { // Vertical-Right
|
||||
const __m128i ABCD0 = _mm_srli_si128(XABCD, 1);
|
||||
const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0);
|
||||
const __m128i _XABCD = _mm_slli_si128(XABCD, 1);
|
||||
const __m128i IXABCD = _mm_insert_epi16(_XABCD, I | (X << 8), 0);
|
||||
const __m128i IXABCD = _mm_insert_epi16(_XABCD, (short)(I | (X << 8)), 0);
|
||||
const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0);
|
||||
const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one);
|
||||
const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
|
||||
|
||||
Vendored
+1
-1
@@ -777,7 +777,7 @@ static WEBP_INLINE void VR4_SSE2(uint8_t* dst,
|
||||
const __m128i ABCD0 = _mm_srli_si128(XABCD, 1);
|
||||
const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0);
|
||||
const __m128i _XABCD = _mm_slli_si128(XABCD, 1);
|
||||
const __m128i IXABCD = _mm_insert_epi16(_XABCD, I | (X << 8), 0);
|
||||
const __m128i IXABCD = _mm_insert_epi16(_XABCD, (short)(I | (X << 8)), 0);
|
||||
const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0);
|
||||
const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one);
|
||||
const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
|
||||
|
||||
Vendored
+6
-6
@@ -33,9 +33,9 @@ static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred,
|
||||
uint8_t* dst, int length, int inverse) {
|
||||
int i;
|
||||
if (inverse) {
|
||||
for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i];
|
||||
for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] + pred[i]);
|
||||
} else {
|
||||
for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i];
|
||||
for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] - pred[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
|
||||
const int pred = GradientPredictor_C(preds[w - 1],
|
||||
preds[w - stride],
|
||||
preds[w - stride - 1]);
|
||||
out[w] = in[w] + (inverse ? pred : -pred);
|
||||
out[w] = (uint8_t)(in[w] + (inverse ? pred : -pred));
|
||||
}
|
||||
++row;
|
||||
preds += stride;
|
||||
@@ -194,7 +194,7 @@ static void HorizontalUnfilter_C(const uint8_t* prev, const uint8_t* in,
|
||||
uint8_t pred = (prev == NULL) ? 0 : prev[0];
|
||||
int i;
|
||||
for (i = 0; i < width; ++i) {
|
||||
out[i] = pred + in[i];
|
||||
out[i] = (uint8_t)(pred + in[i]);
|
||||
pred = out[i];
|
||||
}
|
||||
}
|
||||
@@ -206,7 +206,7 @@ static void VerticalUnfilter_C(const uint8_t* prev, const uint8_t* in,
|
||||
HorizontalUnfilter_C(NULL, in, out, width);
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < width; ++i) out[i] = prev[i] + in[i];
|
||||
for (i = 0; i < width; ++i) out[i] = (uint8_t)(prev[i] + in[i]);
|
||||
}
|
||||
}
|
||||
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||
@@ -220,7 +220,7 @@ static void GradientUnfilter_C(const uint8_t* prev, const uint8_t* in,
|
||||
int i;
|
||||
for (i = 0; i < width; ++i) {
|
||||
top = prev[i]; // need to read this first, in case prev==out
|
||||
left = in[i] + GradientPredictor_C(left, top, top_left);
|
||||
left = (uint8_t)(in[i] + GradientPredictor_C(left, top, top_left));
|
||||
top_left = top;
|
||||
out[i] = left;
|
||||
}
|
||||
|
||||
+9
-7
@@ -163,7 +163,8 @@ static void GradientPredictDirect_SSE2(const uint8_t* const row,
|
||||
_mm_storel_epi64((__m128i*)(out + i), H);
|
||||
}
|
||||
for (; i < length; ++i) {
|
||||
out[i] = row[i] - GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]);
|
||||
const int delta = GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]);
|
||||
out[i] = (uint8_t)(row[i] - delta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +189,7 @@ static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in,
|
||||
|
||||
// Filter line-by-line.
|
||||
while (row < last_row) {
|
||||
out[0] = in[0] - in[-stride];
|
||||
out[0] = (uint8_t)(in[0] - in[-stride]);
|
||||
GradientPredictDirect_SSE2(in + 1, in + 1 - stride, out + 1, width - 1);
|
||||
++row;
|
||||
in += stride;
|
||||
@@ -223,7 +224,7 @@ static void HorizontalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
|
||||
uint8_t* out, int width) {
|
||||
int i;
|
||||
__m128i last;
|
||||
out[0] = in[0] + (prev == NULL ? 0 : prev[0]);
|
||||
out[0] = (uint8_t)(in[0] + (prev == NULL ? 0 : prev[0]));
|
||||
if (width <= 1) return;
|
||||
last = _mm_set_epi32(0, 0, 0, out[0]);
|
||||
for (i = 1; i + 8 <= width; i += 8) {
|
||||
@@ -238,7 +239,7 @@ static void HorizontalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
|
||||
_mm_storel_epi64((__m128i*)(out + i), A7);
|
||||
last = _mm_srli_epi64(A7, 56);
|
||||
}
|
||||
for (; i < width; ++i) out[i] = in[i] + out[i - 1];
|
||||
for (; i < width; ++i) out[i] = (uint8_t)(in[i] + out[i - 1]);
|
||||
}
|
||||
|
||||
static void VerticalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
|
||||
@@ -259,7 +260,7 @@ static void VerticalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
|
||||
_mm_storeu_si128((__m128i*)&out[i + 0], C0);
|
||||
_mm_storeu_si128((__m128i*)&out[i + 16], C1);
|
||||
}
|
||||
for (; i < width; ++i) out[i] = in[i] + prev[i];
|
||||
for (; i < width; ++i) out[i] = (uint8_t)(in[i] + prev[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +297,8 @@ static void GradientPredictInverse_SSE2(const uint8_t* const in,
|
||||
_mm_storel_epi64((__m128i*)&row[i], out);
|
||||
}
|
||||
for (; i < length; ++i) {
|
||||
row[i] = in[i] + GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]);
|
||||
const int delta = GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]);
|
||||
row[i] = (uint8_t)(in[i] + delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,7 +308,7 @@ static void GradientUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
|
||||
if (prev == NULL) {
|
||||
HorizontalUnfilter_SSE2(NULL, in, out, width);
|
||||
} else {
|
||||
out[0] = in[0] + prev[0]; // predict from above
|
||||
out[0] = (uint8_t)(in[0] + prev[0]); // predict from above
|
||||
GradientPredictInverse_SSE2(in + 1, prev + 1, out + 1, width - 1);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -270,14 +270,14 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,
|
||||
int i;
|
||||
for (i = 0; i < num_pixels; ++i) {
|
||||
const uint32_t argb = src[i];
|
||||
const uint32_t green = argb >> 8;
|
||||
const int8_t green = (int8_t)(argb >> 8);
|
||||
const uint32_t red = argb >> 16;
|
||||
int new_red = red & 0xff;
|
||||
int new_blue = argb & 0xff;
|
||||
new_red += ColorTransformDelta(m->green_to_red_, green);
|
||||
new_red &= 0xff;
|
||||
new_blue += ColorTransformDelta(m->green_to_blue_, green);
|
||||
new_blue += ColorTransformDelta(m->red_to_blue_, new_red);
|
||||
new_blue += ColorTransformDelta(m->red_to_blue_, (int8_t)new_red);
|
||||
new_blue &= 0xff;
|
||||
dst[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
|
||||
}
|
||||
|
||||
+13
-8
@@ -515,13 +515,17 @@ static WEBP_INLINE int ColorTransformDelta(int8_t color_pred, int8_t color) {
|
||||
return ((int)color_pred * color) >> 5;
|
||||
}
|
||||
|
||||
static WEBP_INLINE int8_t U32ToS8(uint32_t v) {
|
||||
return (int8_t)(v & 0xff);
|
||||
}
|
||||
|
||||
void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data,
|
||||
int num_pixels) {
|
||||
int i;
|
||||
for (i = 0; i < num_pixels; ++i) {
|
||||
const uint32_t argb = data[i];
|
||||
const uint32_t green = argb >> 8;
|
||||
const uint32_t red = argb >> 16;
|
||||
const int8_t green = U32ToS8(argb >> 8);
|
||||
const int8_t red = U32ToS8(argb >> 16);
|
||||
int new_red = red & 0xff;
|
||||
int new_blue = argb & 0xff;
|
||||
new_red -= ColorTransformDelta(m->green_to_red_, green);
|
||||
@@ -535,7 +539,7 @@ void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data,
|
||||
|
||||
static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red,
|
||||
uint32_t argb) {
|
||||
const uint32_t green = argb >> 8;
|
||||
const int8_t green = U32ToS8(argb >> 8);
|
||||
int new_red = argb >> 16;
|
||||
new_red -= ColorTransformDelta(green_to_red, green);
|
||||
return (new_red & 0xff);
|
||||
@@ -544,9 +548,9 @@ static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red,
|
||||
static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue,
|
||||
uint8_t red_to_blue,
|
||||
uint32_t argb) {
|
||||
const uint32_t green = argb >> 8;
|
||||
const uint32_t red = argb >> 16;
|
||||
uint8_t new_blue = argb;
|
||||
const int8_t green = U32ToS8(argb >> 8);
|
||||
const int8_t red = U32ToS8(argb >> 16);
|
||||
uint8_t new_blue = argb & 0xff;
|
||||
new_blue -= ColorTransformDelta(green_to_blue, green);
|
||||
new_blue -= ColorTransformDelta(red_to_blue, red);
|
||||
return (new_blue & 0xff);
|
||||
@@ -558,7 +562,7 @@ void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride,
|
||||
while (tile_height-- > 0) {
|
||||
int x;
|
||||
for (x = 0; x < tile_width; ++x) {
|
||||
++histo[TransformColorRed(green_to_red, argb[x])];
|
||||
++histo[TransformColorRed((uint8_t)green_to_red, argb[x])];
|
||||
}
|
||||
argb += stride;
|
||||
}
|
||||
@@ -571,7 +575,8 @@ void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride,
|
||||
while (tile_height-- > 0) {
|
||||
int x;
|
||||
for (x = 0; x < tile_width; ++x) {
|
||||
++histo[TransformColorBlue(green_to_blue, red_to_blue, argb[x])];
|
||||
++histo[TransformColorBlue((uint8_t)green_to_blue, (uint8_t)red_to_blue,
|
||||
argb[x])];
|
||||
}
|
||||
argb += stride;
|
||||
}
|
||||
|
||||
+2
-2
@@ -363,7 +363,7 @@ static void BundleColorMap_SSE2(const uint8_t* const row, int width, int xbits,
|
||||
assert(xbits <= 3);
|
||||
switch (xbits) {
|
||||
case 0: {
|
||||
const __m128i ff = _mm_set1_epi16(0xff00);
|
||||
const __m128i ff = _mm_set1_epi16((short)0xff00);
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
// Store 0xff000000 | (row[x] << 8).
|
||||
for (x = 0; x + 16 <= width; x += 16, dst += 16) {
|
||||
@@ -382,7 +382,7 @@ static void BundleColorMap_SSE2(const uint8_t* const row, int width, int xbits,
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
const __m128i ff = _mm_set1_epi16(0xff00);
|
||||
const __m128i ff = _mm_set1_epi16((short)0xff00);
|
||||
const __m128i mul = _mm_set1_epi16(0x110);
|
||||
for (x = 0; x + 16 <= width; x += 16, dst += 8) {
|
||||
// 0a0b | (where a/b are 4 bits).
|
||||
|
||||
+3
-3
@@ -51,9 +51,9 @@ static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride,
|
||||
int histo[]) {
|
||||
const __m128i mults_r = _mm_set1_epi16(CST_5b(red_to_blue));
|
||||
const __m128i mults_g = _mm_set1_epi16(CST_5b(green_to_blue));
|
||||
const __m128i mask_g = _mm_set1_epi16(0xff00); // green mask
|
||||
const __m128i mask_gb = _mm_set1_epi32(0xffff); // green/blue mask
|
||||
const __m128i mask_b = _mm_set1_epi16(0x00ff); // blue mask
|
||||
const __m128i mask_g = _mm_set1_epi16((short)0xff00); // green mask
|
||||
const __m128i mask_gb = _mm_set1_epi32(0xffff); // green/blue mask
|
||||
const __m128i mask_b = _mm_set1_epi16(0x00ff); // blue mask
|
||||
const __m128i shuffler_lo = _mm_setr_epi8(-1, 2, -1, 6, -1, 10, -1, 14, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1);
|
||||
const __m128i shuffler_hi = _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
|
||||
Vendored
+15
@@ -10,6 +10,8 @@
|
||||
#ifndef WEBP_DSP_QUANT_H_
|
||||
#define WEBP_DSP_QUANT_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/webp/types.h"
|
||||
|
||||
@@ -67,4 +69,17 @@ static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks,
|
||||
#endif // defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) &&
|
||||
// !defined(WEBP_HAVE_NEON_RTCD)
|
||||
|
||||
static WEBP_INLINE int IsFlatSource16(const uint8_t* src) {
|
||||
const uint32_t v = src[0] * 0x01010101u;
|
||||
int i;
|
||||
for (i = 0; i < 16; ++i) {
|
||||
if (memcmp(src + 0, &v, 4) || memcmp(src + 4, &v, 4) ||
|
||||
memcmp(src + 8, &v, 4) || memcmp(src + 12, &v, 4)) {
|
||||
return 0;
|
||||
}
|
||||
src += BPS;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // WEBP_DSP_QUANT_H_
|
||||
|
||||
Vendored
+6
-10
@@ -109,8 +109,7 @@ void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
|
||||
for (x_out = 0; x_out < x_out_max; ++x_out) {
|
||||
const uint32_t J = frow[x_out];
|
||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
}
|
||||
} else {
|
||||
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
||||
@@ -120,8 +119,7 @@ void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
|
||||
+ (uint64_t)B * irow[x_out];
|
||||
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,17 +136,15 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
|
||||
assert(!wrk->y_expand);
|
||||
if (yscale) {
|
||||
for (x_out = 0; x_out < x_out_max; ++x_out) {
|
||||
const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
|
||||
const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale);
|
||||
const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
irow[x_out] = frac; // new fractional start
|
||||
}
|
||||
} else {
|
||||
for (x_out = 0; x_out < x_out_max; ++x_out) {
|
||||
const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
irow[x_out] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-10
@@ -107,10 +107,9 @@ static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
|
||||
);
|
||||
}
|
||||
for (i = 0; i < (x_out_max & 0x3); ++i) {
|
||||
const uint32_t frac = (uint32_t)MULT_FIX(*frow++, yscale);
|
||||
const int v = (int)MULT_FIX_FLOOR(*irow - frac, wrk->fxy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
*dst++ = v;
|
||||
const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(*frow++, yscale);
|
||||
const int v = (int)MULT_FIX(*irow - frac, wrk->fxy_scale);
|
||||
*dst++ = (v > 255) ? 255u : (uint8_t)v;
|
||||
*irow++ = frac; // new fractional start
|
||||
}
|
||||
} else {
|
||||
@@ -157,8 +156,7 @@ static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
|
||||
}
|
||||
for (i = 0; i < (x_out_max & 0x3); ++i) {
|
||||
const int v = (int)MULT_FIX_FLOOR(*irow, wrk->fxy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
*dst++ = v;
|
||||
*dst++ = (v > 255) ? 255u : (uint8_t)v;
|
||||
*irow++ = 0;
|
||||
}
|
||||
}
|
||||
@@ -219,8 +217,7 @@ static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
|
||||
for (i = 0; i < (x_out_max & 0x3); ++i) {
|
||||
const uint32_t J = *frow++;
|
||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
*dst++ = v;
|
||||
*dst++ = (v > 255) ? 255u : (uint8_t)v;
|
||||
}
|
||||
} else {
|
||||
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
||||
@@ -291,8 +288,7 @@ static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
|
||||
+ (uint64_t)B * *irow++;
|
||||
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
*dst++ = v;
|
||||
*dst++ = (v > 255) ? 255u : (uint8_t)v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-10
@@ -166,8 +166,7 @@ static WEBP_INLINE void ExportRowExpand_0(const uint32_t* frow, uint8_t* dst,
|
||||
for (x_out = 0; x_out < length; ++x_out) {
|
||||
const uint32_t J = frow[x_out];
|
||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,8 +240,7 @@ static WEBP_INLINE void ExportRowExpand_1(const uint32_t* frow, uint32_t* irow,
|
||||
+ (uint64_t)B * irow[x_out];
|
||||
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,10 +340,9 @@ static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow,
|
||||
length -= 4;
|
||||
}
|
||||
for (x_out = 0; x_out < length; ++x_out) {
|
||||
const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
|
||||
const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale);
|
||||
const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
irow[x_out] = frac;
|
||||
}
|
||||
}
|
||||
@@ -406,8 +403,7 @@ static WEBP_INLINE void ExportRowShrink_1(uint32_t* irow, uint8_t* dst,
|
||||
}
|
||||
for (x_out = 0; x_out < length; ++x_out) {
|
||||
const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
irow[x_out] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-18
@@ -81,14 +81,13 @@ static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
|
||||
const uint32x4_t B1 = MULT_FIX(A1, fy_scale_half);
|
||||
const uint16x4_t C0 = vmovn_u32(B0);
|
||||
const uint16x4_t C1 = vmovn_u32(B1);
|
||||
const uint8x8_t D = vmovn_u16(vcombine_u16(C0, C1));
|
||||
const uint8x8_t D = vqmovn_u16(vcombine_u16(C0, C1));
|
||||
vst1_u8(dst + x_out, D);
|
||||
}
|
||||
for (; x_out < x_out_max; ++x_out) {
|
||||
const uint32_t J = frow[x_out];
|
||||
const int v = (int)MULT_FIX_C(J, fy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
}
|
||||
} else {
|
||||
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
||||
@@ -102,7 +101,7 @@ static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
|
||||
const uint32x4_t D1 = MULT_FIX(C1, fy_scale_half);
|
||||
const uint16x4_t E0 = vmovn_u32(D0);
|
||||
const uint16x4_t E1 = vmovn_u32(D1);
|
||||
const uint8x8_t F = vmovn_u16(vcombine_u16(E0, E1));
|
||||
const uint8x8_t F = vqmovn_u16(vcombine_u16(E0, E1));
|
||||
vst1_u8(dst + x_out, F);
|
||||
}
|
||||
for (; x_out < x_out_max; ++x_out) {
|
||||
@@ -110,8 +109,7 @@ static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
|
||||
+ (uint64_t)B * irow[x_out];
|
||||
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
||||
const int v = (int)MULT_FIX_C(J, fy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,23 +133,22 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
|
||||
for (x_out = 0; x_out < max_span; x_out += 8) {
|
||||
LOAD_32x8(frow + x_out, in0, in1);
|
||||
LOAD_32x8(irow + x_out, in2, in3);
|
||||
const uint32x4_t A0 = MULT_FIX(in0, yscale_half);
|
||||
const uint32x4_t A1 = MULT_FIX(in1, yscale_half);
|
||||
const uint32x4_t A0 = MULT_FIX_FLOOR(in0, yscale_half);
|
||||
const uint32x4_t A1 = MULT_FIX_FLOOR(in1, yscale_half);
|
||||
const uint32x4_t B0 = vqsubq_u32(in2, A0);
|
||||
const uint32x4_t B1 = vqsubq_u32(in3, A1);
|
||||
const uint32x4_t C0 = MULT_FIX_FLOOR(B0, fxy_scale_half);
|
||||
const uint32x4_t C1 = MULT_FIX_FLOOR(B1, fxy_scale_half);
|
||||
const uint32x4_t C0 = MULT_FIX(B0, fxy_scale_half);
|
||||
const uint32x4_t C1 = MULT_FIX(B1, fxy_scale_half);
|
||||
const uint16x4_t D0 = vmovn_u32(C0);
|
||||
const uint16x4_t D1 = vmovn_u32(C1);
|
||||
const uint8x8_t E = vmovn_u16(vcombine_u16(D0, D1));
|
||||
const uint8x8_t E = vqmovn_u16(vcombine_u16(D0, D1));
|
||||
vst1_u8(dst + x_out, E);
|
||||
STORE_32x8(A0, A1, irow + x_out);
|
||||
}
|
||||
for (; x_out < x_out_max; ++x_out) {
|
||||
const uint32_t frac = (uint32_t)MULT_FIX_C(frow[x_out], yscale);
|
||||
const int v = (int)MULT_FIX_FLOOR_C(irow[x_out] - frac, fxy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
const uint32_t frac = (uint32_t)MULT_FIX_FLOOR_C(frow[x_out], yscale);
|
||||
const int v = (int)MULT_FIX_C(irow[x_out] - frac, fxy_scale);
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
irow[x_out] = frac; // new fractional start
|
||||
}
|
||||
} else {
|
||||
@@ -161,14 +158,13 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
|
||||
const uint32x4_t A1 = MULT_FIX(in1, fxy_scale_half);
|
||||
const uint16x4_t B0 = vmovn_u32(A0);
|
||||
const uint16x4_t B1 = vmovn_u32(A1);
|
||||
const uint8x8_t C = vmovn_u16(vcombine_u16(B0, B1));
|
||||
const uint8x8_t C = vqmovn_u16(vcombine_u16(B0, B1));
|
||||
vst1_u8(dst + x_out, C);
|
||||
STORE_32x8(zero, zero, irow + x_out);
|
||||
}
|
||||
for (; x_out < x_out_max; ++x_out) {
|
||||
const int v = (int)MULT_FIX_C(irow[x_out], fxy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
irow[x_out] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-49
@@ -225,35 +225,6 @@ static WEBP_INLINE void ProcessRow_SSE2(const __m128i* const A0,
|
||||
_mm_storel_epi64((__m128i*)dst, G);
|
||||
}
|
||||
|
||||
static WEBP_INLINE void ProcessRow_Floor_SSE2(const __m128i* const A0,
|
||||
const __m128i* const A1,
|
||||
const __m128i* const A2,
|
||||
const __m128i* const A3,
|
||||
const __m128i* const mult,
|
||||
uint8_t* const dst) {
|
||||
const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
|
||||
const __m128i B0 = _mm_mul_epu32(*A0, *mult);
|
||||
const __m128i B1 = _mm_mul_epu32(*A1, *mult);
|
||||
const __m128i B2 = _mm_mul_epu32(*A2, *mult);
|
||||
const __m128i B3 = _mm_mul_epu32(*A3, *mult);
|
||||
const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX);
|
||||
const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX);
|
||||
#if (WEBP_RESCALER_RFIX < 32)
|
||||
const __m128i D2 =
|
||||
_mm_and_si128(_mm_slli_epi64(B2, 32 - WEBP_RESCALER_RFIX), mask);
|
||||
const __m128i D3 =
|
||||
_mm_and_si128(_mm_slli_epi64(B3, 32 - WEBP_RESCALER_RFIX), mask);
|
||||
#else
|
||||
const __m128i D2 = _mm_and_si128(B2, mask);
|
||||
const __m128i D3 = _mm_and_si128(B3, mask);
|
||||
#endif
|
||||
const __m128i E0 = _mm_or_si128(D0, D2);
|
||||
const __m128i E1 = _mm_or_si128(D1, D3);
|
||||
const __m128i F = _mm_packs_epi32(E0, E1);
|
||||
const __m128i G = _mm_packus_epi16(F, F);
|
||||
_mm_storel_epi64((__m128i*)dst, G);
|
||||
}
|
||||
|
||||
static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
|
||||
int x_out;
|
||||
uint8_t* const dst = wrk->dst;
|
||||
@@ -274,8 +245,7 @@ static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
|
||||
for (; x_out < x_out_max; ++x_out) {
|
||||
const uint32_t J = frow[x_out];
|
||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
}
|
||||
} else {
|
||||
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
|
||||
@@ -308,8 +278,7 @@ static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
|
||||
+ (uint64_t)B * irow[x_out];
|
||||
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
|
||||
const int v = (int)MULT_FIX(J, wrk->fy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,20 +297,15 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
|
||||
const int scale_xy = wrk->fxy_scale;
|
||||
const __m128i mult_xy = _mm_set_epi32(0, scale_xy, 0, scale_xy);
|
||||
const __m128i mult_y = _mm_set_epi32(0, yscale, 0, yscale);
|
||||
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
|
||||
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
|
||||
__m128i A0, A1, A2, A3, B0, B1, B2, B3;
|
||||
LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3);
|
||||
LoadDispatchAndMult_SSE2(frow + x_out, &mult_y, &B0, &B1, &B2, &B3);
|
||||
{
|
||||
const __m128i C0 = _mm_add_epi64(B0, rounder);
|
||||
const __m128i C1 = _mm_add_epi64(B1, rounder);
|
||||
const __m128i C2 = _mm_add_epi64(B2, rounder);
|
||||
const __m128i C3 = _mm_add_epi64(B3, rounder);
|
||||
const __m128i D0 = _mm_srli_epi64(C0, WEBP_RESCALER_RFIX); // = frac
|
||||
const __m128i D1 = _mm_srli_epi64(C1, WEBP_RESCALER_RFIX);
|
||||
const __m128i D2 = _mm_srli_epi64(C2, WEBP_RESCALER_RFIX);
|
||||
const __m128i D3 = _mm_srli_epi64(C3, WEBP_RESCALER_RFIX);
|
||||
const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX); // = frac
|
||||
const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX);
|
||||
const __m128i D2 = _mm_srli_epi64(B2, WEBP_RESCALER_RFIX);
|
||||
const __m128i D3 = _mm_srli_epi64(B3, WEBP_RESCALER_RFIX);
|
||||
const __m128i E0 = _mm_sub_epi64(A0, D0); // irow[x] - frac
|
||||
const __m128i E1 = _mm_sub_epi64(A1, D1);
|
||||
const __m128i E2 = _mm_sub_epi64(A2, D2);
|
||||
@@ -352,14 +316,13 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
|
||||
const __m128i G1 = _mm_or_si128(D1, F3);
|
||||
_mm_storeu_si128((__m128i*)(irow + x_out + 0), G0);
|
||||
_mm_storeu_si128((__m128i*)(irow + x_out + 4), G1);
|
||||
ProcessRow_Floor_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
|
||||
ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
|
||||
}
|
||||
}
|
||||
for (; x_out < x_out_max; ++x_out) {
|
||||
const uint32_t frac = (int)MULT_FIX(frow[x_out], yscale);
|
||||
const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
const uint32_t frac = (int)MULT_FIX_FLOOR(frow[x_out], yscale);
|
||||
const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
irow[x_out] = frac; // new fractional start
|
||||
}
|
||||
} else {
|
||||
@@ -375,8 +338,7 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
|
||||
}
|
||||
for (; x_out < x_out_max; ++x_out) {
|
||||
const int v = (int)MULT_FIX(irow[x_out], scale);
|
||||
assert(v >= 0 && v <= 255);
|
||||
dst[x_out] = v;
|
||||
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
|
||||
irow[x_out] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -191,13 +191,14 @@ void VP8LHashChainClear(VP8LHashChain* const p) {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define HASH_MULTIPLIER_HI (0xc6a4a793ULL)
|
||||
#define HASH_MULTIPLIER_LO (0x5bd1e996ULL)
|
||||
static const uint32_t kHashMultiplierHi = 0xc6a4a793u;
|
||||
static const uint32_t kHashMultiplierLo = 0x5bd1e996u;
|
||||
|
||||
static WEBP_INLINE uint32_t GetPixPairHash64(const uint32_t* const argb) {
|
||||
static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
|
||||
uint32_t GetPixPairHash64(const uint32_t* const argb) {
|
||||
uint32_t key;
|
||||
key = (argb[1] * HASH_MULTIPLIER_HI) & 0xffffffffu;
|
||||
key += (argb[0] * HASH_MULTIPLIER_LO) & 0xffffffffu;
|
||||
key = argb[1] * kHashMultiplierHi;
|
||||
key += argb[0] * kHashMultiplierLo;
|
||||
key = key >> (32 - HASH_BITS);
|
||||
return key;
|
||||
}
|
||||
|
||||
+2
-3
@@ -929,9 +929,8 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
|
||||
}
|
||||
|
||||
mappings = (int*) WebPSafeMalloc(*num_used, sizeof(*mappings));
|
||||
if (mappings == NULL || !HistoQueueInit(&histo_queue, kHistoQueueSize)) {
|
||||
goto End;
|
||||
}
|
||||
if (mappings == NULL) return 0;
|
||||
if (!HistoQueueInit(&histo_queue, kHistoQueueSize)) goto End;
|
||||
// Fill the initial mapping.
|
||||
for (j = 0, iter = 0; iter < image_histo->size; ++iter) {
|
||||
if (histograms[iter] == NULL) continue;
|
||||
|
||||
+7
-7
@@ -202,7 +202,7 @@ static uint32_t NearLossless(uint32_t value, uint32_t predict,
|
||||
}
|
||||
if ((value >> 24) == 0 || (value >> 24) == 0xff) {
|
||||
// Preserve transparency of fully transparent or fully opaque pixels.
|
||||
a = NearLosslessDiff(value >> 24, predict >> 24);
|
||||
a = NearLosslessDiff((value >> 24) & 0xff, (predict >> 24) & 0xff);
|
||||
} else {
|
||||
a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization);
|
||||
}
|
||||
@@ -215,12 +215,12 @@ static uint32_t NearLossless(uint32_t value, uint32_t predict,
|
||||
// The amount by which green has been adjusted during quantization. It is
|
||||
// subtracted from red and blue for compensation, to avoid accumulating two
|
||||
// quantization errors in them.
|
||||
green_diff = NearLosslessDiff(new_green, value >> 8);
|
||||
green_diff = NearLosslessDiff(new_green, (value >> 8) & 0xff);
|
||||
}
|
||||
r = NearLosslessComponent(NearLosslessDiff(value >> 16, green_diff),
|
||||
r = NearLosslessComponent(NearLosslessDiff((value >> 16) & 0xff, green_diff),
|
||||
(predict >> 16) & 0xff, 0xff - new_green,
|
||||
quantization);
|
||||
b = NearLosslessComponent(NearLosslessDiff(value, green_diff),
|
||||
b = NearLosslessComponent(NearLosslessDiff(value & 0xff, green_diff),
|
||||
predict & 0xff, 0xff - new_green, quantization);
|
||||
return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
}
|
||||
@@ -587,7 +587,7 @@ static void GetBestGreenToRed(
|
||||
}
|
||||
}
|
||||
}
|
||||
best_tx->green_to_red_ = green_to_red_best;
|
||||
best_tx->green_to_red_ = (green_to_red_best & 0xff);
|
||||
}
|
||||
|
||||
static float GetPredictionCostCrossColorBlue(
|
||||
@@ -666,8 +666,8 @@ static void GetBestGreenRedToBlue(
|
||||
break; // out of iter-loop.
|
||||
}
|
||||
}
|
||||
best_tx->green_to_blue_ = green_to_blue_best;
|
||||
best_tx->red_to_blue_ = red_to_blue_best;
|
||||
best_tx->green_to_blue_ = green_to_blue_best & 0xff;
|
||||
best_tx->red_to_blue_ = red_to_blue_best & 0xff;
|
||||
}
|
||||
#undef kGreenRedToBlueMaxIters
|
||||
#undef kGreenRedToBlueNumAxis
|
||||
|
||||
Vendored
+20
-6
@@ -33,7 +33,7 @@
|
||||
|
||||
// number of non-zero coeffs below which we consider the block very flat
|
||||
// (and apply a penalty to complex predictions)
|
||||
#define FLATNESS_LIMIT_I16 10 // I16 mode
|
||||
#define FLATNESS_LIMIT_I16 0 // I16 mode (special case)
|
||||
#define FLATNESS_LIMIT_I4 3 // I4 mode
|
||||
#define FLATNESS_LIMIT_UV 2 // UV mode
|
||||
#define FLATNESS_PENALTY 140 // roughly ~1bit per block
|
||||
@@ -988,6 +988,7 @@ static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
|
||||
VP8ModeScore* rd_cur = &rd_tmp;
|
||||
VP8ModeScore* rd_best = rd;
|
||||
int mode;
|
||||
int is_flat = IsFlatSource16(it->yuv_in_ + Y_OFF_ENC);
|
||||
|
||||
rd->mode_i16 = -1;
|
||||
for (mode = 0; mode < NUM_PRED_MODES; ++mode) {
|
||||
@@ -1003,10 +1004,14 @@ static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
|
||||
tlambda ? MULT_8B(tlambda, VP8TDisto16x16(src, tmp_dst, kWeightY)) : 0;
|
||||
rd_cur->H = VP8FixedCostsI16[mode];
|
||||
rd_cur->R = VP8GetCostLuma16(it, rd_cur);
|
||||
if (mode > 0 &&
|
||||
IsFlat(rd_cur->y_ac_levels[0], kNumBlocks, FLATNESS_LIMIT_I16)) {
|
||||
// penalty to avoid flat area to be mispredicted by complex mode
|
||||
rd_cur->R += FLATNESS_PENALTY * kNumBlocks;
|
||||
if (is_flat) {
|
||||
// refine the first impression (which was in pixel space)
|
||||
is_flat = IsFlat(rd_cur->y_ac_levels[0], kNumBlocks, FLATNESS_LIMIT_I16);
|
||||
if (is_flat) {
|
||||
// Block is very flat. We put emphasis on the distortion being very low!
|
||||
rd_cur->D *= 2;
|
||||
rd_cur->SD *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Since we always examine Intra16 first, we can overwrite *rd directly.
|
||||
@@ -1087,7 +1092,8 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
|
||||
: 0;
|
||||
rd_tmp.H = mode_costs[mode];
|
||||
|
||||
// Add flatness penalty
|
||||
// Add flatness penalty, to avoid flat area to be mispredicted
|
||||
// by a complex mode.
|
||||
if (mode > 0 && IsFlat(tmp_levels, kNumBlocks, FLATNESS_LIMIT_I4)) {
|
||||
rd_tmp.R = FLATNESS_PENALTY * kNumBlocks;
|
||||
} else {
|
||||
@@ -1242,11 +1248,19 @@ static void RefineUsingDistortion(VP8EncIterator* const it,
|
||||
if (mode > 0 && VP8FixedCostsI16[mode] > bit_limit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (score < best_score) {
|
||||
best_mode = mode;
|
||||
best_score = score;
|
||||
}
|
||||
}
|
||||
if (it->x_ == 0 || it->y_ == 0) {
|
||||
// avoid starting a checkerboard resonance from the border. See bug #432.
|
||||
if (IsFlatSource16(src)) {
|
||||
best_mode = (it->x_ == 0) ? 0 : 2;
|
||||
try_both_modes = 0; // stick to i16
|
||||
}
|
||||
}
|
||||
VP8SetIntra16Mode(it, best_mode);
|
||||
// we'll reconstruct later, if i16 mode actually gets selected
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -32,7 +32,7 @@ extern "C" {
|
||||
// version numbers
|
||||
#define ENC_MAJ_VERSION 1
|
||||
#define ENC_MIN_VERSION 0
|
||||
#define ENC_REV_VERSION 2
|
||||
#define ENC_REV_VERSION 3
|
||||
|
||||
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
|
||||
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
|
||||
|
||||
Vendored
+1
-1
@@ -29,7 +29,7 @@ extern "C" {
|
||||
|
||||
#define MUX_MAJ_VERSION 1
|
||||
#define MUX_MIN_VERSION 0
|
||||
#define MUX_REV_VERSION 2
|
||||
#define MUX_REV_VERSION 3
|
||||
|
||||
// Chunk object.
|
||||
typedef struct WebPChunk WebPChunk;
|
||||
|
||||
+8
-3
@@ -104,7 +104,8 @@ void VP8LoadNewBytes(VP8BitReader* const br) {
|
||||
}
|
||||
|
||||
// Read a bit with proba 'prob'. Speed-critical function!
|
||||
static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) {
|
||||
static WEBP_INLINE int VP8GetBit(VP8BitReader* const br,
|
||||
int prob, const char label[]) {
|
||||
// Don't move this declaration! It makes a big speed difference to store
|
||||
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
|
||||
// alter br->range_ value.
|
||||
@@ -129,13 +130,14 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) {
|
||||
br->bits_ -= shift;
|
||||
}
|
||||
br->range_ = range - 1;
|
||||
BT_TRACK(br);
|
||||
return bit;
|
||||
}
|
||||
}
|
||||
|
||||
// simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here)
|
||||
static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
|
||||
int VP8GetSigned(VP8BitReader* const br, int v) {
|
||||
int VP8GetSigned(VP8BitReader* const br, int v, const char label[]) {
|
||||
if (br->bits_ < 0) {
|
||||
VP8LoadNewBytes(br);
|
||||
}
|
||||
@@ -148,11 +150,13 @@ int VP8GetSigned(VP8BitReader* const br, int v) {
|
||||
br->range_ += mask;
|
||||
br->range_ |= 1;
|
||||
br->value_ -= (bit_t)((split + 1) & mask) << pos;
|
||||
BT_TRACK(br);
|
||||
return (v ^ mask) - mask;
|
||||
}
|
||||
}
|
||||
|
||||
static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) {
|
||||
static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br,
|
||||
int prob, const char label[]) {
|
||||
// Don't move this declaration! It makes a big speed difference to store
|
||||
// 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
|
||||
// alter br->range_ value.
|
||||
@@ -179,6 +183,7 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) {
|
||||
br->bits_ -= shift;
|
||||
}
|
||||
br->range_ = range;
|
||||
BT_TRACK(br);
|
||||
return bit;
|
||||
}
|
||||
}
|
||||
|
||||
+81
-5
@@ -102,17 +102,18 @@ void VP8LoadFinalBytes(VP8BitReader* const br) {
|
||||
//------------------------------------------------------------------------------
|
||||
// Higher-level calls
|
||||
|
||||
uint32_t VP8GetValue(VP8BitReader* const br, int bits) {
|
||||
uint32_t VP8GetValue(VP8BitReader* const br, int bits, const char label[]) {
|
||||
uint32_t v = 0;
|
||||
while (bits-- > 0) {
|
||||
v |= VP8GetBit(br, 0x80) << bits;
|
||||
v |= VP8GetBit(br, 0x80, label) << bits;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) {
|
||||
const int value = VP8GetValue(br, bits);
|
||||
return VP8Get(br) ? -value : value;
|
||||
int32_t VP8GetSignedValue(VP8BitReader* const br, int bits,
|
||||
const char label[]) {
|
||||
const int value = VP8GetValue(br, bits, label);
|
||||
return VP8Get(br, label) ? -value : value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -220,3 +221,78 @@ uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) {
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Bit-tracing tool
|
||||
|
||||
#if (BITTRACE > 0)
|
||||
|
||||
#include <stdlib.h> // for atexit()
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_NUM_LABELS 32
|
||||
static struct {
|
||||
const char* label;
|
||||
int size;
|
||||
int count;
|
||||
} kLabels[MAX_NUM_LABELS];
|
||||
|
||||
static int last_label = 0;
|
||||
static int last_pos = 0;
|
||||
static const uint8_t* buf_start = NULL;
|
||||
static int init_done = 0;
|
||||
|
||||
static void PrintBitTraces(void) {
|
||||
int i;
|
||||
int scale = 1;
|
||||
int total = 0;
|
||||
const char* units = "bits";
|
||||
#if (BITTRACE == 2)
|
||||
scale = 8;
|
||||
units = "bytes";
|
||||
#endif
|
||||
for (i = 0; i < last_label; ++i) total += kLabels[i].size;
|
||||
if (total < 1) total = 1; // avoid rounding errors
|
||||
printf("=== Bit traces ===\n");
|
||||
for (i = 0; i < last_label; ++i) {
|
||||
const int skip = 16 - (int)strlen(kLabels[i].label);
|
||||
const int value = (kLabels[i].size + scale - 1) / scale;
|
||||
assert(skip > 0);
|
||||
printf("%s \%*s: %6d %s \t[%5.2f%%] [count: %7d]\n",
|
||||
kLabels[i].label, skip, "", value, units,
|
||||
100.f * kLabels[i].size / total,
|
||||
kLabels[i].count);
|
||||
}
|
||||
total = (total + scale - 1) / scale;
|
||||
printf("Total: %d %s\n", total, units);
|
||||
}
|
||||
|
||||
void BitTrace(const struct VP8BitReader* const br, const char label[]) {
|
||||
int i, pos;
|
||||
if (!init_done) {
|
||||
memset(kLabels, 0, sizeof(kLabels));
|
||||
atexit(PrintBitTraces);
|
||||
buf_start = br->buf_;
|
||||
init_done = 1;
|
||||
}
|
||||
pos = (int)(br->buf_ - buf_start) * 8 - br->bits_;
|
||||
// if there's a too large jump, we've changed partition -> reset counter
|
||||
if (abs(pos - last_pos) > 32) {
|
||||
buf_start = br->buf_;
|
||||
pos = 0;
|
||||
last_pos = 0;
|
||||
}
|
||||
if (br->range_ >= 0x7f) pos += kVP8Log2Range[br->range_ - 0x7f];
|
||||
for (i = 0; i < last_label; ++i) {
|
||||
if (!strcmp(label, kLabels[i].label)) break;
|
||||
}
|
||||
if (i == MAX_NUM_LABELS) abort(); // overflow!
|
||||
kLabels[i].label = label;
|
||||
kLabels[i].size += pos - last_pos;
|
||||
kLabels[i].count += 1;
|
||||
if (i == last_label) ++last_label;
|
||||
last_pos = pos;
|
||||
}
|
||||
|
||||
#endif // BITTRACE > 0
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
+26
-7
@@ -21,6 +21,27 @@
|
||||
#endif
|
||||
#include "src/webp/types.h"
|
||||
|
||||
// Warning! This macro triggers quite some MACRO wizardry around func signature!
|
||||
#if !defined(BITTRACE)
|
||||
#define BITTRACE 0 // 0 = off, 1 = print bits, 2 = print bytes
|
||||
#endif
|
||||
|
||||
#if (BITTRACE > 0)
|
||||
struct VP8BitReader;
|
||||
extern void BitTrace(const struct VP8BitReader* const br, const char label[]);
|
||||
#define BT_TRACK(br) BitTrace(br, label)
|
||||
#define VP8Get(BR, L) VP8GetValue(BR, 1, L)
|
||||
#else
|
||||
#define BT_TRACK(br)
|
||||
// We'll REMOVE the 'const char label[]' from all signatures and calls (!!):
|
||||
#define VP8GetValue(BR, N, L) VP8GetValue(BR, N)
|
||||
#define VP8Get(BR, L) VP8GetValue(BR, 1, L)
|
||||
#define VP8GetSignedValue(BR, N, L) VP8GetSignedValue(BR, N)
|
||||
#define VP8GetBit(BR, P, L) VP8GetBit(BR, P)
|
||||
#define VP8GetBitAlt(BR, P, L) VP8GetBitAlt(BR, P)
|
||||
#define VP8GetSigned(BR, V, L) VP8GetSigned(BR, V)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -92,17 +113,15 @@ void VP8BitReaderSetBuffer(VP8BitReader* const br,
|
||||
void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset);
|
||||
|
||||
// return the next value made of 'num_bits' bits
|
||||
uint32_t VP8GetValue(VP8BitReader* const br, int num_bits);
|
||||
static WEBP_INLINE uint32_t VP8Get(VP8BitReader* const br) {
|
||||
return VP8GetValue(br, 1);
|
||||
}
|
||||
uint32_t VP8GetValue(VP8BitReader* const br, int num_bits, const char label[]);
|
||||
|
||||
// return the next value with sign-extension.
|
||||
int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits);
|
||||
int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits,
|
||||
const char label[]);
|
||||
|
||||
// bit_reader_inl.h will implement the following methods:
|
||||
// static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob)
|
||||
// static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v)
|
||||
// static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob, ...)
|
||||
// static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v, ...)
|
||||
// and should be included by the .c files that actually need them.
|
||||
// This is to avoid recompiling the whole library whenever this file is touched,
|
||||
// and also allowing platform-specific ad-hoc hacks.
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ static void Flush(VP8BitWriter* const bw) {
|
||||
const int value = (bits & 0x100) ? 0x00 : 0xff;
|
||||
for (; bw->run_ > 0; --bw->run_) bw->buf_[pos++] = value;
|
||||
}
|
||||
bw->buf_[pos++] = bits;
|
||||
bw->buf_[pos++] = bits & 0xff;
|
||||
bw->pos_ = pos;
|
||||
} else {
|
||||
bw->run_++; // delay writing of bytes 0xff, pending eventual carry.
|
||||
|
||||
+5
-3
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "src/dsp/dsp.h"
|
||||
#include "src/webp/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -30,10 +31,11 @@ typedef struct {
|
||||
int hash_bits_;
|
||||
} VP8LColorCache;
|
||||
|
||||
static const uint64_t kHashMul = 0x1e35a7bdull;
|
||||
static const uint32_t kHashMul = 0x1e35a7bdu;
|
||||
|
||||
static WEBP_INLINE int VP8LHashPix(uint32_t argb, int shift) {
|
||||
return (int)(((argb * kHashMul) & 0xffffffffu) >> shift);
|
||||
static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE
|
||||
int VP8LHashPix(uint32_t argb, int shift) {
|
||||
return (int)((argb * kHashMul) >> shift);
|
||||
}
|
||||
|
||||
static WEBP_INLINE uint32_t VP8LColorCacheLookup(
|
||||
|
||||
+19
-7
@@ -91,7 +91,8 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
|
||||
assert(code_lengths_size != 0);
|
||||
assert(code_lengths != NULL);
|
||||
assert(root_table != NULL);
|
||||
assert((root_table != NULL && sorted != NULL) ||
|
||||
(root_table == NULL && sorted == NULL));
|
||||
assert(root_bits > 0);
|
||||
|
||||
// Build histogram of code lengths.
|
||||
@@ -120,16 +121,22 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
|
||||
const int symbol_code_length = code_lengths[symbol];
|
||||
if (code_lengths[symbol] > 0) {
|
||||
sorted[offset[symbol_code_length]++] = symbol;
|
||||
if (sorted != NULL) {
|
||||
sorted[offset[symbol_code_length]++] = symbol;
|
||||
} else {
|
||||
offset[symbol_code_length]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Special case code with only one value.
|
||||
if (offset[MAX_ALLOWED_CODE_LENGTH] == 1) {
|
||||
HuffmanCode code;
|
||||
code.bits = 0;
|
||||
code.value = (uint16_t)sorted[0];
|
||||
ReplicateValue(table, 1, total_size, code);
|
||||
if (sorted != NULL) {
|
||||
HuffmanCode code;
|
||||
code.bits = 0;
|
||||
code.value = (uint16_t)sorted[0];
|
||||
ReplicateValue(table, 1, total_size, code);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
@@ -151,6 +158,7 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
if (num_open < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (root_table == NULL) continue;
|
||||
for (; count[len] > 0; --count[len]) {
|
||||
HuffmanCode code;
|
||||
code.bits = (uint8_t)len;
|
||||
@@ -169,6 +177,7 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
if (num_open < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (root_table == NULL) continue;
|
||||
for (; count[len] > 0; --count[len]) {
|
||||
HuffmanCode code;
|
||||
if ((key & mask) != low) {
|
||||
@@ -206,7 +215,10 @@ int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
const int code_lengths[], int code_lengths_size) {
|
||||
int total_size;
|
||||
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
|
||||
if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
|
||||
if (root_table == NULL) {
|
||||
total_size = BuildHuffmanTable(NULL, root_bits,
|
||||
code_lengths, code_lengths_size, NULL);
|
||||
} else if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
|
||||
// use local stack-allocated array.
|
||||
uint16_t sorted[SORTED_SIZE_CUTOFF];
|
||||
total_size = BuildHuffmanTable(root_table, root_bits,
|
||||
|
||||
+2
@@ -78,6 +78,8 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
|
||||
// the huffman table.
|
||||
// Returns built table size or 0 in case of error (invalid tree or
|
||||
// memory error).
|
||||
// If root_table is NULL, it returns 0 if a lookup cannot be built, something
|
||||
// > 0 otherwise (but not the table size).
|
||||
int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||
const int code_lengths[], int code_lengths_size);
|
||||
|
||||
|
||||
+4
-4
@@ -84,14 +84,14 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
|
||||
int height = *scaled_height;
|
||||
|
||||
// if width is unspecified, scale original proportionally to height ratio.
|
||||
if (width == 0) {
|
||||
if (width == 0 && src_height > 0) {
|
||||
width =
|
||||
(int)(((uint64_t)src_width * height + src_height / 2) / src_height);
|
||||
(int)(((uint64_t)src_width * height + src_height - 1) / src_height);
|
||||
}
|
||||
// if height is unspecified, scale original proportionally to width ratio.
|
||||
if (height == 0) {
|
||||
if (height == 0 && src_width > 0) {
|
||||
height =
|
||||
(int)(((uint64_t)src_height * width + src_width / 2) / src_width);
|
||||
(int)(((uint64_t)src_height * width + src_width - 1) / src_width);
|
||||
}
|
||||
// Check if the overall dimensions still make sense.
|
||||
if (width <= 0 || height <= 0) {
|
||||
|
||||
+11
-1
@@ -217,8 +217,12 @@ static THREADFN ThreadLoop(void* ptr) {
|
||||
done = 1;
|
||||
}
|
||||
// signal to the main thread that we're done (for Sync())
|
||||
pthread_cond_signal(&impl->condition_);
|
||||
// Note the associated mutex does not need to be held when signaling the
|
||||
// condition. Unlocking the mutex first may improve performance in some
|
||||
// implementations, avoiding the case where the waiting thread can't
|
||||
// reacquire the mutex when woken.
|
||||
pthread_mutex_unlock(&impl->mutex_);
|
||||
pthread_cond_signal(&impl->condition_);
|
||||
}
|
||||
return THREAD_RETURN(NULL); // Thread is finished
|
||||
}
|
||||
@@ -240,7 +244,13 @@ static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) {
|
||||
// assign new status and release the working thread if needed
|
||||
if (new_status != OK) {
|
||||
worker->status_ = new_status;
|
||||
// Note the associated mutex does not need to be held when signaling the
|
||||
// condition. Unlocking the mutex first may improve performance in some
|
||||
// implementations, avoiding the case where the waiting thread can't
|
||||
// reacquire the mutex when woken.
|
||||
pthread_mutex_unlock(&impl->mutex_);
|
||||
pthread_cond_signal(&impl->condition_);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&impl->mutex_);
|
||||
|
||||
Vendored
+3
-3
@@ -92,14 +92,14 @@ static WEBP_INLINE uint32_t GetLE32(const uint8_t* const data) {
|
||||
// Store 16, 24 or 32 bits in little-endian order.
|
||||
static WEBP_INLINE void PutLE16(uint8_t* const data, int val) {
|
||||
assert(val < (1 << 16));
|
||||
data[0] = (val >> 0);
|
||||
data[1] = (val >> 8);
|
||||
data[0] = (val >> 0) & 0xff;
|
||||
data[1] = (val >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static WEBP_INLINE void PutLE24(uint8_t* const data, int val) {
|
||||
assert(val < (1 << 24));
|
||||
PutLE16(data, val & 0xffff);
|
||||
data[2] = (val >> 16);
|
||||
data[2] = (val >> 16) & 0xff;
|
||||
}
|
||||
|
||||
static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
|
||||
|
||||
Vendored
+4
@@ -62,6 +62,10 @@ WEBP_EXTERN size_t WebPEncodeBGRA(const uint8_t* bgra,
|
||||
// These functions are the equivalent of the above, but compressing in a
|
||||
// lossless manner. Files are usually larger than lossy format, but will
|
||||
// not suffer any compression loss.
|
||||
// Note these functions, like the lossy versions, use the library's default
|
||||
// settings. For lossless this means 'exact' is disabled. RGB values in
|
||||
// transparent areas will be modified to improve compression. To avoid this,
|
||||
// use WebPEncode() and set WebPConfig::exact to 1.
|
||||
WEBP_EXTERN size_t WebPEncodeLosslessRGB(const uint8_t* rgb,
|
||||
int width, int height, int stride,
|
||||
uint8_t** output);
|
||||
|
||||
Vendored
+1
-1
@@ -45,7 +45,7 @@
|
||||
|
||||
|
||||
// GCC and Visual Studio SSE2 compiler flags
|
||||
#if defined __SSE2__ || (_MSC_VER >= 1300 && !_M_CEE_PURE)
|
||||
#if defined __SSE2__ || (defined(_M_X64) || _M_IX86_FP == 2)
|
||||
#define IMF_HAVE_SSE2 1
|
||||
#endif
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -5,7 +5,7 @@ target_include_directories(openvx_hal PUBLIC
|
||||
${CMAKE_SOURCE_DIR}/modules/core/include
|
||||
${CMAKE_SOURCE_DIR}/modules/imgproc/include
|
||||
${OPENVX_INCLUDE_DIR})
|
||||
target_link_libraries(openvx_hal LINK_PUBLIC ${OPENVX_LIBRARIES})
|
||||
target_link_libraries(openvx_hal PUBLIC ${OPENVX_LIBRARIES})
|
||||
set_target_properties(openvx_hal PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH})
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
ocv_install_target(openvx_hal EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev)
|
||||
|
||||
Vendored
+1
@@ -22,6 +22,7 @@ else()
|
||||
-Wenum-compare-switch
|
||||
-Wsuggest-override -Winconsistent-missing-override
|
||||
-Wimplicit-fallthrough
|
||||
-Warray-bounds # GCC 9+
|
||||
)
|
||||
endif()
|
||||
if(CV_ICC)
|
||||
|
||||
Vendored
+6
-3
@@ -5,10 +5,11 @@ if (WIN32 AND NOT ARM)
|
||||
message(FATAL_ERROR "BUILD_TBB option supports Windows on ARM only!\nUse regular official TBB build instead of the BUILD_TBB option!")
|
||||
endif()
|
||||
|
||||
ocv_update(OPENCV_TBB_RELEASE "2019_U8")
|
||||
ocv_update(OPENCV_TBB_RELEASE_MD5 "7c371d0f62726154d2c568a85697a0ad")
|
||||
ocv_update(OPENCV_TBB_RELEASE "v2020.0")
|
||||
ocv_update(OPENCV_TBB_RELEASE_MD5 "5858dd01ec007c139d5d178b21e06dae")
|
||||
ocv_update(OPENCV_TBB_FILENAME "${OPENCV_TBB_RELEASE}.tar.gz")
|
||||
ocv_update(OPENCV_TBB_SUBDIR "tbb-${OPENCV_TBB_RELEASE}")
|
||||
string(REGEX REPLACE "^v" "" OPENCV_TBB_RELEASE_ "${OPENCV_TBB_RELEASE}")
|
||||
ocv_update(OPENCV_TBB_SUBDIR "tbb-${OPENCV_TBB_RELEASE_}")
|
||||
|
||||
set(tbb_src_dir "${OpenCV_BINARY_DIR}/3rdparty/tbb")
|
||||
ocv_download(FILENAME ${OPENCV_TBB_FILENAME}
|
||||
@@ -34,10 +35,12 @@ ocv_include_directories("${tbb_src_dir}/include"
|
||||
file(GLOB lib_srcs "${tbb_src_dir}/src/tbb/*.cpp")
|
||||
file(GLOB lib_hdrs "${tbb_src_dir}/src/tbb/*.h")
|
||||
list(APPEND lib_srcs "${tbb_src_dir}/src/rml/client/rml_tbb.cpp")
|
||||
ocv_list_filterout(lib_srcs "${tbb_src_dir}/src/tbb/tbbbind.cpp") # hwloc.h requirement
|
||||
|
||||
if (WIN32)
|
||||
add_definitions(/D__TBB_DYNAMIC_LOAD_ENABLED=0
|
||||
/D__TBB_BUILD=1
|
||||
/DTBB_SUPPRESS_DEPRECATED_MESSAGES=1
|
||||
/DTBB_NO_LEGACY=1
|
||||
/D_UNICODE
|
||||
/DUNICODE
|
||||
|
||||
+30
-2
@@ -276,6 +276,9 @@ OCV_OPTION(WITH_HALIDE "Include Halide support" OFF
|
||||
OCV_OPTION(WITH_INF_ENGINE "Include Intel Inference Engine support" OFF
|
||||
VISIBLE_IF TRUE
|
||||
VERIFY INF_ENGINE_TARGET)
|
||||
OCV_OPTION(WITH_NGRAPH "Include nGraph support" WITH_INF_ENGINE
|
||||
VISIBLE_IF TRUE
|
||||
VERIFY TARGET ngraph::ngraph)
|
||||
OCV_OPTION(WITH_JASPER "Include JPEG2K support" ON
|
||||
VISIBLE_IF NOT IOS
|
||||
VERIFY HAVE_JASPER)
|
||||
@@ -1489,12 +1492,37 @@ if(WITH_INF_ENGINE OR INF_ENGINE_TARGET)
|
||||
)
|
||||
get_target_property(_inc ${ie_target} INTERFACE_INCLUDE_DIRECTORIES)
|
||||
status(" Inference Engine:" "${__msg}")
|
||||
status(" libs:" "${_lib}")
|
||||
status(" includes:" "${_inc}")
|
||||
status(" * libs:" "${_lib}")
|
||||
status(" * includes:" "${_inc}")
|
||||
else()
|
||||
status(" Inference Engine:" "NO")
|
||||
endif()
|
||||
endif()
|
||||
if(WITH_NGRAPH OR HAVE_NGRAPH)
|
||||
if(HAVE_NGRAPH)
|
||||
set(__target ngraph::ngraph)
|
||||
set(__msg "YES (${ngraph_VERSION})")
|
||||
get_target_property(_lib ${__target} IMPORTED_LOCATION)
|
||||
get_target_property(_lib_imp_rel ${__target} IMPORTED_IMPLIB_RELEASE)
|
||||
get_target_property(_lib_imp_dbg ${__target} IMPORTED_IMPLIB_DEBUG)
|
||||
get_target_property(_lib_rel ${__target} IMPORTED_LOCATION_RELEASE)
|
||||
get_target_property(_lib_dbg ${__target} IMPORTED_LOCATION_DEBUG)
|
||||
ocv_build_features_string(_lib
|
||||
IF _lib THEN "${_lib}"
|
||||
IF _lib_imp_rel AND _lib_imp_dbg THEN "${_lib_imp_rel} / ${_lib_imp_dbg}"
|
||||
IF _lib_rel AND _lib_dbg THEN "${_lib_rel} / ${_lib_dbg}"
|
||||
IF _lib_rel THEN "${_lib_rel}"
|
||||
IF _lib_dbg THEN "${_lib_dbg}"
|
||||
ELSE "unknown"
|
||||
)
|
||||
get_target_property(_inc ${__target} INTERFACE_INCLUDE_DIRECTORIES)
|
||||
status(" nGraph:" "${__msg}")
|
||||
status(" * libs:" "${_lib}")
|
||||
status(" * includes:" "${_inc}")
|
||||
else()
|
||||
status(" nGraph:" "NO")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_EIGEN OR HAVE_EIGEN)
|
||||
status(" Eigen:" HAVE_EIGEN THEN "YES (ver ${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION})" ELSE NO)
|
||||
|
||||
@@ -13,6 +13,7 @@ Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved.
|
||||
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
|
||||
Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
|
||||
Copyright (C) 2015-2016, Itseez Inc., all rights reserved.
|
||||
Copyright (C) 2019, Xperience AI, all rights reserved.
|
||||
Third party copyrights are property of their respective owners.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
|
||||
@@ -288,7 +288,7 @@ if(X86 OR X86_64)
|
||||
ocv_update(CPU_AVX2_FLAGS_ON "/arch:AVX2")
|
||||
ocv_update(CPU_AVX_FLAGS_ON "/arch:AVX")
|
||||
ocv_update(CPU_FP16_FLAGS_ON "/arch:AVX")
|
||||
if(NOT MSVC64)
|
||||
if(NOT X86_64)
|
||||
# 64-bit MSVC compiler uses SSE/SSE2 by default
|
||||
ocv_update(CPU_SSE_FLAGS_ON "/arch:SSE")
|
||||
ocv_update(CPU_SSE_SUPPORTED ON)
|
||||
@@ -346,7 +346,7 @@ elseif(MIPS)
|
||||
ocv_update(CPU_MSA_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_msa.cpp")
|
||||
ocv_update(CPU_KNOWN_OPTIMIZATIONS "MSA")
|
||||
ocv_update(CPU_MSA_FLAGS_ON "-mmsa")
|
||||
set(CPU_BASELINE "MSA" CACHE STRING "${HELP_CPU_BASELINE}")
|
||||
set(CPU_BASELINE "DETECT" CACHE STRING "${HELP_CPU_BASELINE}")
|
||||
elseif(PPC64LE)
|
||||
ocv_update(CPU_KNOWN_OPTIMIZATIONS "VSX;VSX3")
|
||||
ocv_update(CPU_VSX_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_vsx.cpp")
|
||||
@@ -714,7 +714,10 @@ macro(ocv_compiler_optimization_process_sources SOURCES_VAR_NAME LIBS_VAR_NAME T
|
||||
foreach(OPT ${CPU_DISPATCH_FINAL})
|
||||
if(__result_${OPT})
|
||||
#message("${OPT}: ${__result_${OPT}}")
|
||||
if(CMAKE_GENERATOR MATCHES "^Visual")
|
||||
if(CMAKE_GENERATOR MATCHES "^Visual"
|
||||
OR OPENCV_CMAKE_CPU_OPTIMIZATIONS_FORCE_TARGETS
|
||||
)
|
||||
# MSVS generator is not able to properly order compilation flags:
|
||||
# extra flags are added before common flags, so switching between optimizations doesn't work correctly
|
||||
# Also CMAKE_CXX_FLAGS doesn't work (it is directory-based, so add_subdirectory is required)
|
||||
add_library(${TARGET_BASE_NAME}_${OPT} OBJECT ${__result_${OPT}})
|
||||
|
||||
@@ -383,6 +383,19 @@ if(MSVC)
|
||||
add_definitions(-D_VARIADIC_MAX=10)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
get_directory_property(__DIRECTORY_COMPILE_DEFINITIONS COMPILE_DEFINITIONS)
|
||||
if((NOT " ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE} ${OPENCV_EXTRA_CXX_FLAGS} ${OPENCV_EXTRA_FLAGS_RELEASE} ${__DIRECTORY_COMPILE_DEFINITIONS}" MATCHES "_WIN32_WINNT"
|
||||
AND NOT OPENCV_CMAKE_SKIP_MACRO_WIN32_WINNT)
|
||||
OR OPENCV_CMAKE_FORCE_MACRO_WIN32_WINNT
|
||||
)
|
||||
# https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
|
||||
# Target Windows 7 API
|
||||
set(OPENCV_CMAKE_MACRO_WIN32_WINNT "0x0601" CACHE STRING "Value of _WIN32_WINNT macro")
|
||||
add_definitions(-D_WIN32_WINNT=${OPENCV_CMAKE_MACRO_WIN32_WINNT})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Enable compiler options for OpenCV modules/apps/samples only (ignore 3rdparty)
|
||||
macro(ocv_add_modules_compiler_options)
|
||||
if(MSVC AND NOT OPENCV_SKIP_MSVC_W4_OPTION)
|
||||
|
||||
@@ -12,7 +12,7 @@ endif()
|
||||
if(((NOT CMAKE_VERSION VERSION_LESS "3.9.0") # requires https://gitlab.kitware.com/cmake/cmake/merge_requests/663
|
||||
OR OPENCV_CUDA_FORCE_EXTERNAL_CMAKE_MODULE)
|
||||
AND NOT OPENCV_CUDA_FORCE_BUILTIN_CMAKE_MODULE)
|
||||
ocv_update(CUDA_LINK_LIBRARIES_KEYWORD "LINK_PRIVATE")
|
||||
ocv_update(CUDA_LINK_LIBRARIES_KEYWORD "PRIVATE")
|
||||
find_host_package(CUDA "${MIN_VER_CUDA}" QUIET)
|
||||
else()
|
||||
# Use OpenCV's patched "FindCUDA" module
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
# - CV_CLANG - Clang-compatible compiler (CMAKE_CXX_COMPILER_ID MATCHES "Clang" - Clang or AppleClang, see CMP0025)
|
||||
# - CV_ICC - Intel compiler
|
||||
# - MSVC - Microsoft Visual Compiler (CMake variable)
|
||||
# - MSVC64 - additional flag, 64-bit
|
||||
# - MINGW / CYGWIN / CMAKE_COMPILER_IS_MINGW / CMAKE_COMPILER_IS_CYGWIN (CMake original variables)
|
||||
# - MINGW64 - 64-bit
|
||||
#
|
||||
# CPU Platforms:
|
||||
# - X86 / X86_64
|
||||
# - ARM - ARM CPU, not defined for AArch64
|
||||
# - AARCH64 - ARMv8+ (64-bit)
|
||||
# - PPC64 / PPC64LE - PowerPC
|
||||
# - MIPS
|
||||
#
|
||||
# OS:
|
||||
# - WIN32 - Windows | MINGW
|
||||
@@ -21,9 +20,8 @@
|
||||
# - APPLE - MacOSX | iOS
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if(CMAKE_CL_64)
|
||||
set(MSVC64 1)
|
||||
endif()
|
||||
ocv_declare_removed_variables(MINGW64 MSVC64)
|
||||
# do not use (CMake variables): CMAKE_CL_64
|
||||
|
||||
if(NOT DEFINED CV_GCC AND CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
set(CV_GCC 1)
|
||||
@@ -51,7 +49,7 @@ variable_watch(CMAKE_COMPILER_IS_CLANGCC access_CMAKE_COMPILER_IS_CLANGCXX)
|
||||
# Detect Intel ICC compiler
|
||||
# ----------------------------------------------------------------------------
|
||||
if(UNIX)
|
||||
if (__ICL)
|
||||
if(__ICL)
|
||||
set(CV_ICC __ICL)
|
||||
elseif(__ICC)
|
||||
set(CV_ICC __ICC)
|
||||
@@ -70,53 +68,65 @@ if(MSVC AND CMAKE_C_COMPILER MATCHES "icc|icl")
|
||||
set(CV_ICC __INTEL_COMPILER_FOR_WINDOWS)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_CXX_COMPILER_VERSION)
|
||||
message(WARNING "Compiler version is not available: CMAKE_CXX_COMPILER_VERSION is not set")
|
||||
if(NOT DEFINED CMAKE_CXX_COMPILER_VERSION
|
||||
AND NOT OPENCV_SUPPRESS_MESSAGE_MISSING_COMPILER_VERSION)
|
||||
message(WARNING "OpenCV: Compiler version is not available: CMAKE_CXX_COMPILER_VERSION is not set")
|
||||
endif()
|
||||
|
||||
if(WIN32 AND CV_GCC)
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpmachine
|
||||
OUTPUT_VARIABLE OPENCV_GCC_TARGET_MACHINE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(OPENCV_GCC_TARGET_MACHINE MATCHES "amd64|x86_64|AMD64")
|
||||
set(MINGW64 1)
|
||||
endif()
|
||||
if((NOT DEFINED CMAKE_SYSTEM_PROCESSOR OR CMAKE_SYSTEM_PROCESSOR STREQUAL "")
|
||||
AND NOT OPENCV_SUPPRESS_MESSAGE_MISSING_CMAKE_SYSTEM_PROCESSOR)
|
||||
message(WARNING "OpenCV: CMAKE_SYSTEM_PROCESSOR is not defined. Perhaps CMake toolchain is broken")
|
||||
endif()
|
||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P
|
||||
AND NOT OPENCV_SUPPRESS_MESSAGE_MISSING_CMAKE_SIZEOF_VOID_P)
|
||||
message(WARNING "OpenCV: CMAKE_SIZEOF_VOID_P is not defined. Perhaps CMake toolchain is broken")
|
||||
endif()
|
||||
|
||||
message(STATUS "Detected processor: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
if(MSVC64 OR MINGW64)
|
||||
set(X86_64 1)
|
||||
elseif(MINGW OR (MSVC AND NOT CMAKE_CROSSCOMPILING))
|
||||
set(X86 1)
|
||||
if(OPENCV_SKIP_SYSTEM_PROCESSOR_DETECTION)
|
||||
# custom setup: required variables are passed through cache / CMake's command-line
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*")
|
||||
set(X86_64 1)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*|amd64.*|AMD64.*")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*")
|
||||
set(X86 1)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*|arm64.*|ARM64.*)")
|
||||
set(AARCH64 1)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)")
|
||||
set(ARM 1)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)")
|
||||
set(AARCH64 1)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64le")
|
||||
set(PPC64LE 1)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
|
||||
set(PPC64 1)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(mips.*|MIPS.*)")
|
||||
set(MIPS 1)
|
||||
else()
|
||||
if(NOT OPENCV_SUPPRESS_MESSAGE_UNRECOGNIZED_SYSTEM_PROCESSOR)
|
||||
message(WARNING "OpenCV: unrecognized target processor configuration")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Workaround for 32-bit operating systems on x86_64/aarch64 processor
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4 AND NOT FORCE_X86_64)
|
||||
# Workaround for 32-bit operating systems on x86_64
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4 AND X86_64
|
||||
AND NOT FORCE_X86_64 # deprecated (2019-12)
|
||||
AND NOT OPENCV_FORCE_X86_64
|
||||
)
|
||||
message(STATUS "sizeof(void) = 4 on 64 bit processor. Assume 32-bit compilation mode")
|
||||
if (X86_64)
|
||||
if(X86_64)
|
||||
unset(X86_64)
|
||||
set(X86 1)
|
||||
endif()
|
||||
if (AARCH64)
|
||||
endif()
|
||||
# Workaround for 32-bit operating systems on aarch64 processor
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4 AND AARCH64
|
||||
AND NOT OPENCV_FORCE_AARCH64
|
||||
)
|
||||
message(STATUS "sizeof(void) = 4 on 64 bit processor. Assume 32-bit compilation mode")
|
||||
if(AARCH64)
|
||||
unset(AARCH64)
|
||||
set(ARM 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# Similar code exists in OpenCVConfig.cmake
|
||||
if(NOT DEFINED OpenCV_STATIC)
|
||||
# look for global setting
|
||||
@@ -130,14 +140,19 @@ endif()
|
||||
if(DEFINED OpenCV_ARCH AND DEFINED OpenCV_RUNTIME)
|
||||
# custom overridden values
|
||||
elseif(MSVC)
|
||||
if(CMAKE_CL_64)
|
||||
set(OpenCV_ARCH x64)
|
||||
elseif((CMAKE_GENERATOR MATCHES "ARM") OR ("${arch_hint}" STREQUAL "ARM") OR (CMAKE_VS_EFFECTIVE_PLATFORMS MATCHES "ARM|arm"))
|
||||
# see Modules/CmakeGenericSystem.cmake
|
||||
set(OpenCV_ARCH ARM)
|
||||
# see Modules/CMakeGenericSystem.cmake
|
||||
if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
|
||||
set(OpenCV_ARCH "x64")
|
||||
elseif("${CMAKE_GENERATOR_PLATFORM}" MATCHES "ARM64")
|
||||
set(OpenCV_ARCH "ARM64")
|
||||
elseif("${CMAKE_GENERATOR}" MATCHES "ARM")
|
||||
set(OpenCV_ARCH "ARM")
|
||||
elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
set(OpenCV_ARCH "x64")
|
||||
else()
|
||||
set(OpenCV_ARCH x86)
|
||||
endif()
|
||||
|
||||
if(MSVC_VERSION EQUAL 1400)
|
||||
set(OpenCV_RUNTIME vc8)
|
||||
elseif(MSVC_VERSION EQUAL 1500)
|
||||
@@ -160,7 +175,7 @@ elseif(MSVC)
|
||||
elseif(MINGW)
|
||||
set(OpenCV_RUNTIME mingw)
|
||||
|
||||
if(MINGW64)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*")
|
||||
set(OpenCV_ARCH x64)
|
||||
else()
|
||||
set(OpenCV_ARCH x86)
|
||||
|
||||
@@ -35,6 +35,15 @@ function(add_custom_ie_build _inc _lib _lib_rel _lib_dbg _msg)
|
||||
IMPORTED_IMPLIB_DEBUG "${_lib_dbg}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_inc}"
|
||||
)
|
||||
|
||||
find_library(ie_builder_custom_lib "inference_engine_nn_builder" PATHS "${INF_ENGINE_LIB_DIRS}" NO_DEFAULT_PATH)
|
||||
if(EXISTS "${ie_builder_custom_lib}")
|
||||
add_library(inference_engine_nn_builder UNKNOWN IMPORTED)
|
||||
set_target_properties(inference_engine_nn_builder PROPERTIES
|
||||
IMPORTED_LOCATION "${ie_builder_custom_lib}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT INF_ENGINE_RELEASE VERSION_GREATER "2018050000")
|
||||
find_library(INF_ENGINE_OMP_LIBRARY iomp5 PATHS "${INF_ENGINE_OMP_DIR}" NO_DEFAULT_PATH)
|
||||
if(NOT INF_ENGINE_OMP_LIBRARY)
|
||||
@@ -44,7 +53,12 @@ function(add_custom_ie_build _inc _lib _lib_rel _lib_dbg _msg)
|
||||
endif()
|
||||
endif()
|
||||
set(INF_ENGINE_VERSION "Unknown" CACHE STRING "")
|
||||
set(INF_ENGINE_TARGET inference_engine PARENT_SCOPE)
|
||||
set(INF_ENGINE_TARGET inference_engine)
|
||||
if(TARGET inference_engine_nn_builder)
|
||||
list(APPEND INF_ENGINE_TARGET inference_engine_nn_builder)
|
||||
set(_msg "${_msg}, with IE NN Builder API")
|
||||
endif()
|
||||
set(INF_ENGINE_TARGET "${INF_ENGINE_TARGET}" PARENT_SCOPE)
|
||||
message(STATUS "Detected InferenceEngine: ${_msg}")
|
||||
endfunction()
|
||||
|
||||
@@ -54,7 +68,7 @@ find_package(InferenceEngine QUIET)
|
||||
if(InferenceEngine_FOUND)
|
||||
set(INF_ENGINE_TARGET ${InferenceEngine_LIBRARIES})
|
||||
set(INF_ENGINE_VERSION "${InferenceEngine_VERSION}" CACHE STRING "")
|
||||
message(STATUS "Detected InferenceEngine: cmake package")
|
||||
message(STATUS "Detected InferenceEngine: cmake package (${InferenceEngine_VERSION})")
|
||||
endif()
|
||||
|
||||
if(NOT INF_ENGINE_TARGET AND INF_ENGINE_LIB_DIRS AND INF_ENGINE_INCLUDE_DIRS)
|
||||
@@ -94,3 +108,15 @@ if(INF_ENGINE_TARGET)
|
||||
INTERFACE_COMPILE_DEFINITIONS "HAVE_INF_ENGINE=1;INF_ENGINE_RELEASE=${INF_ENGINE_RELEASE}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_NGRAPH)
|
||||
find_package(ngraph QUIET)
|
||||
if(ngraph_FOUND)
|
||||
ocv_assert(TARGET ngraph::ngraph)
|
||||
if(INF_ENGINE_RELEASE VERSION_LESS "2019039999")
|
||||
message(WARNING "nGraph is not tested with current InferenceEngine version: INF_ENGINE_RELEASE=${INF_ENGINE_RELEASE}")
|
||||
endif()
|
||||
message(STATUS "Detected ngraph: cmake package (${ngraph_VERSION})")
|
||||
set(HAVE_NGRAPH ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -40,11 +40,8 @@ if (X86 AND UNIX AND NOT APPLE AND NOT ANDROID AND BUILD_SHARED_LIBS)
|
||||
endif()
|
||||
|
||||
set(IPP_X64 0)
|
||||
if(CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8)
|
||||
set(IPP_X64 1)
|
||||
endif()
|
||||
if(CMAKE_CL_64)
|
||||
set(IPP_X64 1)
|
||||
if(X86_64)
|
||||
set(IPP_X64 1)
|
||||
endif()
|
||||
|
||||
# This function detects Intel IPP version by analyzing .h file
|
||||
|
||||
@@ -289,7 +289,7 @@ if(WIN32)
|
||||
if(HAVE_VFW)
|
||||
list(APPEND VIDEOIO_LIBRARIES vfw32)
|
||||
endif()
|
||||
if(MINGW64)
|
||||
if(MINGW AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
list(APPEND VIDEOIO_LIBRARIES avifil32 avicap32 winmm msvfw32)
|
||||
list(REMOVE_ITEM VIDEOIO_LIBRARIES vfw32)
|
||||
elseif(MINGW)
|
||||
|
||||
@@ -133,7 +133,7 @@ message(STATUS "Found MKL ${MKL_VERSION_STR} at: ${MKL_ROOT_DIR}")
|
||||
set(HAVE_MKL ON)
|
||||
set(MKL_ROOT_DIR "${MKL_ROOT_DIR}" CACHE PATH "Path to MKL directory")
|
||||
set(MKL_INCLUDE_DIRS "${MKL_INCLUDE_DIRS}" CACHE PATH "Path to MKL include directory")
|
||||
set(MKL_LIBRARIES "${MKL_LIBRARIES}" CACHE STRING "MKL libarries")
|
||||
set(MKL_LIBRARIES "${MKL_LIBRARIES}" CACHE STRING "MKL libraries")
|
||||
if(UNIX AND NOT MKL_LIBRARIES_DONT_HACK)
|
||||
#it's ugly but helps to avoid cyclic lib problem
|
||||
set(MKL_LIBRARIES ${MKL_LIBRARIES} ${MKL_LIBRARIES} ${MKL_LIBRARIES} "-lpthread" "-lm" "-ldl")
|
||||
|
||||
@@ -15,60 +15,94 @@ file(TO_CMAKE_PATH "$ENV{ProgramFiles}" ProgramFiles_ENV_PATH)
|
||||
|
||||
if(WIN32)
|
||||
SET(OPENEXR_ROOT "C:/Deploy" CACHE STRING "Path to the OpenEXR \"Deploy\" folder")
|
||||
if(CMAKE_CL_64)
|
||||
if(X86_64)
|
||||
SET(OPENEXR_LIBSEARCH_SUFFIXES x64/Release x64 x64/Debug)
|
||||
elseif(MSVC)
|
||||
SET(OPENEXR_LIBSEARCH_SUFFIXES Win32/Release Win32 Win32/Debug)
|
||||
endif()
|
||||
else()
|
||||
set(OPENEXR_ROOT "")
|
||||
endif()
|
||||
|
||||
SET(LIBRARY_PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/sw/lib
|
||||
/opt/local/lib
|
||||
"${ProgramFiles_ENV_PATH}/OpenEXR/lib/static"
|
||||
"${OPENEXR_ROOT}/lib")
|
||||
SET(SEARCH_PATHS
|
||||
"${OPENEXR_ROOT}"
|
||||
/usr
|
||||
/usr/local
|
||||
/sw
|
||||
/opt
|
||||
"${ProgramFiles_ENV_PATH}/OpenEXR")
|
||||
|
||||
FIND_PATH(OPENEXR_INCLUDE_PATH ImfRgbaFile.h
|
||||
PATH_SUFFIXES OpenEXR
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/sw/include
|
||||
/opt/local/include
|
||||
"${ProgramFiles_ENV_PATH}/OpenEXR/include"
|
||||
"${OPENEXR_ROOT}/include")
|
||||
MACRO(FIND_OPENEXR_LIBRARY LIBRARY_NAME LIBRARY_SUFFIX)
|
||||
string(TOUPPER "${LIBRARY_NAME}" LIBRARY_NAME_UPPER)
|
||||
FIND_LIBRARY(OPENEXR_${LIBRARY_NAME_UPPER}_LIBRARY
|
||||
NAMES ${LIBRARY_NAME}${LIBRARY_SUFFIX}
|
||||
PATH_SUFFIXES ${OPENEXR_LIBSEARCH_SUFFIXES}
|
||||
NO_DEFAULT_PATH
|
||||
PATHS "${SEARCH_PATH}/lib" "${SEARCH_PATH}/lib/static")
|
||||
ENDMACRO()
|
||||
|
||||
FIND_LIBRARY(OPENEXR_HALF_LIBRARY
|
||||
NAMES Half
|
||||
PATH_SUFFIXES ${OPENEXR_LIBSEARCH_SUFFIXES}
|
||||
PATHS ${LIBRARY_PATHS})
|
||||
FOREACH(SEARCH_PATH ${SEARCH_PATHS})
|
||||
FIND_PATH(OPENEXR_INCLUDE_PATH ImfRgbaFile.h
|
||||
PATH_SUFFIXES OpenEXR
|
||||
NO_DEFAULT_PATH
|
||||
PATHS
|
||||
"${SEARCH_PATH}/include")
|
||||
|
||||
FIND_LIBRARY(OPENEXR_IEX_LIBRARY
|
||||
NAMES Iex
|
||||
PATH_SUFFIXES ${OPENEXR_LIBSEARCH_SUFFIXES}
|
||||
PATHS ${LIBRARY_PATHS})
|
||||
IF (OPENEXR_INCLUDE_PATH)
|
||||
SET(OPENEXR_VERSION_FILE "${OPENEXR_INCLUDE_PATH}/OpenEXRConfig.h")
|
||||
IF (EXISTS ${OPENEXR_VERSION_FILE})
|
||||
FILE (STRINGS ${OPENEXR_VERSION_FILE} contents REGEX "#define OPENEXR_VERSION_MAJOR ")
|
||||
IF (${contents} MATCHES "#define OPENEXR_VERSION_MAJOR ([0-9]+)")
|
||||
SET(OPENEXR_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
ENDIF ()
|
||||
FILE (STRINGS ${OPENEXR_VERSION_FILE} contents REGEX "#define OPENEXR_VERSION_MINOR ")
|
||||
IF (${contents} MATCHES "#define OPENEXR_VERSION_MINOR ([0-9]+)")
|
||||
SET(OPENEXR_VERSION_MINOR "${CMAKE_MATCH_1}")
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
||||
FIND_LIBRARY(OPENEXR_IMATH_LIBRARY
|
||||
NAMES Imath
|
||||
PATH_SUFFIXES ${OPENEXR_LIBSEARCH_SUFFIXES}
|
||||
PATHS ${LIBRARY_PATHS})
|
||||
IF (OPENEXR_VERSION_MAJOR AND OPENEXR_VERSION_MINOR)
|
||||
set(OPENEXR_VERSION "${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}")
|
||||
ENDIF ()
|
||||
|
||||
FIND_LIBRARY(OPENEXR_ILMIMF_LIBRARY
|
||||
NAMES IlmImf
|
||||
PATH_SUFFIXES ${OPENEXR_LIBSEARCH_SUFFIXES}
|
||||
PATHS ${LIBRARY_PATHS})
|
||||
SET(LIBRARY_SUFFIXES
|
||||
"-${OPENEXR_VERSION}"
|
||||
"-${OPENEXR_VERSION}_s"
|
||||
"-${OPENEXR_VERSION}_d"
|
||||
"-${OPEXEXR_VERSION}_s_d"
|
||||
""
|
||||
"_s"
|
||||
"_d"
|
||||
"_s_d")
|
||||
|
||||
FIND_LIBRARY(OPENEXR_ILMTHREAD_LIBRARY
|
||||
NAMES IlmThread
|
||||
PATH_SUFFIXES ${OPENEXR_LIBSEARCH_SUFFIXES}
|
||||
PATHS ${LIBRARY_PATHS})
|
||||
FOREACH(LIBRARY_SUFFIX ${LIBRARY_SUFFIXES})
|
||||
FIND_OPENEXR_LIBRARY("Half" ${LIBRARY_SUFFIX})
|
||||
FIND_OPENEXR_LIBRARY("Iex" ${LIBRARY_SUFFIX})
|
||||
FIND_OPENEXR_LIBRARY("Imath" ${LIBRARY_SUFFIX})
|
||||
FIND_OPENEXR_LIBRARY("IlmImf" ${LIBRARY_SUFFIX})
|
||||
FIND_OPENEXR_LIBRARY("IlmThread" ${LIBRARY_SUFFIX})
|
||||
IF (OPENEXR_INCLUDE_PATH AND OPENEXR_IMATH_LIBRARY AND OPENEXR_ILMIMF_LIBRARY AND OPENEXR_IEX_LIBRARY AND OPENEXR_HALF_LIBRARY)
|
||||
SET(OPENEXR_FOUND TRUE)
|
||||
BREAK()
|
||||
ENDIF()
|
||||
UNSET(OPENEXR_IMATH_LIBRARY)
|
||||
UNSET(OPENEXR_ILMIMF_LIBRARY)
|
||||
UNSET(OPENEXR_IEX_LIBRARY)
|
||||
UNSET(OPENEXR_ILMTHREAD_LIBRARY)
|
||||
UNSET(OPENEXR_HALF_LIBRARY)
|
||||
ENDFOREACH()
|
||||
|
||||
IF (OPENEXR_INCLUDE_PATH AND OPENEXR_IMATH_LIBRARY AND OPENEXR_ILMIMF_LIBRARY AND OPENEXR_IEX_LIBRARY AND OPENEXR_HALF_LIBRARY)
|
||||
SET(OPENEXR_FOUND TRUE)
|
||||
IF (OPENEXR_FOUND)
|
||||
BREAK()
|
||||
ENDIF()
|
||||
|
||||
UNSET(OPENEXR_INCLUDE_PATH)
|
||||
UNSET(OPENEXR_VERSION_FILE)
|
||||
UNSET(OPENEXR_VERSION_MAJOR)
|
||||
UNSET(OPENEXR_VERSION_MINOR)
|
||||
UNSET(OPENEXR_VERSION)
|
||||
ENDFOREACH()
|
||||
|
||||
IF (OPENEXR_FOUND)
|
||||
SET(OPENEXR_INCLUDE_PATHS ${OPENEXR_INCLUDE_PATH} CACHE PATH "The include paths needed to use OpenEXR")
|
||||
SET(OPENEXR_LIBRARIES ${OPENEXR_IMATH_LIBRARY} ${OPENEXR_ILMIMF_LIBRARY} ${OPENEXR_IEX_LIBRARY} ${OPENEXR_HALF_LIBRARY} ${OPENEXR_ILMTHREAD_LIBRARY} CACHE STRING "The libraries needed to use OpenEXR" FORCE)
|
||||
ENDIF ()
|
||||
|
||||
@@ -18,7 +18,7 @@ if(NOT "${OPENNI_PRIME_SENSOR_MODULE_BIN_DIR}" STREQUAL "${OPENNI_PRIME_SENSOR_M
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
if(NOT (MSVC64 OR MINGW64))
|
||||
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
find_file(OPENNI_INCLUDES "XnCppWrapper.h" PATHS "$ENV{OPEN_NI_INSTALL_PATH}Include" DOC "OpenNI c++ interface header")
|
||||
find_library(OPENNI_LIBRARY "OpenNI" PATHS $ENV{OPEN_NI_LIB} DOC "OpenNI library")
|
||||
else()
|
||||
@@ -34,7 +34,7 @@ if(OPENNI_LIBRARY AND OPENNI_INCLUDES)
|
||||
set(HAVE_OPENNI TRUE)
|
||||
# the check: are PrimeSensor Modules for OpenNI installed
|
||||
if(WIN32)
|
||||
if(NOT (MSVC64 OR MINGW64))
|
||||
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
find_file(OPENNI_PRIME_SENSOR_MODULE "XnCore.dll" PATHS "$ENV{OPEN_NI_INSTALL_PATH}../PrimeSense/Sensor/Bin" "$ENV{OPEN_NI_INSTALL_PATH}../PrimeSense/SensorKinect/Bin" DOC "Core library of PrimeSensor Modules for OpenNI")
|
||||
else()
|
||||
find_file(OPENNI_PRIME_SENSOR_MODULE "XnCore64.dll" PATHS "$ENV{OPEN_NI_INSTALL_PATH64}../PrimeSense/Sensor/Bin64" "$ENV{OPEN_NI_INSTALL_PATH64}../PrimeSense/SensorKinect/Bin64" DOC "Core library of PrimeSensor Modules for OpenNI")
|
||||
|
||||
@@ -13,7 +13,7 @@ if(NOT "${OPENNI2_INCLUDE_DIR}" STREQUAL "${OPENNI2_INCLUDE_DIR_INTERNAL}")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
if(NOT (MSVC64 OR MINGW64))
|
||||
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
find_file(OPENNI2_INCLUDES "OpenNI.h" PATHS $ENV{OPENNI2_INCLUDE} "$ENV{OPEN_NI_INSTALL_PATH}Include" DOC "OpenNI2 c++ interface header")
|
||||
find_library(OPENNI2_LIBRARY "OpenNI2" PATHS $ENV{OPENNI2_LIB} DOC "OpenNI2 library")
|
||||
else()
|
||||
|
||||
@@ -63,7 +63,6 @@ foreach(mod ${OPENCV_MODULES_BUILD} ${OPENCV_MODULES_DISABLED_USER} ${OPENCV_MOD
|
||||
unset(OPENCV_MODULE_${mod}_PRIVATE_OPT_DEPS CACHE)
|
||||
unset(OPENCV_MODULE_${mod}_LINK_DEPS CACHE)
|
||||
unset(OPENCV_MODULE_${mod}_WRAPPERS CACHE)
|
||||
unset(OPENCV_DEPENDANT_TARGETS_${mod} CACHE)
|
||||
endforeach()
|
||||
|
||||
# clean modules info which needs to be recalculated
|
||||
@@ -935,11 +934,15 @@ macro(_ocv_create_module)
|
||||
set_source_files_properties(${OPENCV_MODULE_${the_module}_HEADERS} ${OPENCV_MODULE_${the_module}_SOURCES} ${${the_module}_pch}
|
||||
PROPERTIES LABELS "${OPENCV_MODULE_${the_module}_LABEL};Module")
|
||||
|
||||
ocv_target_link_libraries(${the_module} LINK_PUBLIC ${OPENCV_MODULE_${the_module}_DEPS_TO_LINK})
|
||||
ocv_target_link_libraries(${the_module} LINK_PUBLIC ${OPENCV_MODULE_${the_module}_DEPS_EXT})
|
||||
ocv_target_link_libraries(${the_module} LINK_PRIVATE ${OPENCV_LINKER_LIBS} ${OPENCV_HAL_LINKER_LIBS} ${IPP_LIBS} ${ARGN})
|
||||
ocv_target_link_libraries(${the_module} PUBLIC ${OPENCV_MODULE_${the_module}_DEPS_TO_LINK}
|
||||
INTERFACE ${OPENCV_MODULE_${the_module}_DEPS_TO_LINK}
|
||||
)
|
||||
ocv_target_link_libraries(${the_module} PUBLIC ${OPENCV_MODULE_${the_module}_DEPS_EXT}
|
||||
INTERFACE ${OPENCV_MODULE_${the_module}_DEPS_EXT}
|
||||
)
|
||||
ocv_target_link_libraries(${the_module} PRIVATE ${OPENCV_LINKER_LIBS} ${OPENCV_HAL_LINKER_LIBS} ${IPP_LIBS} ${ARGN})
|
||||
if (HAVE_CUDA)
|
||||
ocv_target_link_libraries(${the_module} LINK_PRIVATE ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY})
|
||||
ocv_target_link_libraries(${the_module} PRIVATE ${CUDA_LIBRARIES} ${CUDA_npp_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(OPENCV_MODULE_${the_module}_COMPILE_DEFINITIONS)
|
||||
@@ -1146,7 +1149,7 @@ function(ocv_add_perf_tests)
|
||||
source_group("Src" FILES "${${the_target}_pch}")
|
||||
ocv_add_executable(${the_target} ${OPENCV_PERF_${the_module}_SOURCES} ${${the_target}_pch})
|
||||
ocv_target_include_modules(${the_target} ${perf_deps})
|
||||
ocv_target_link_libraries(${the_target} LINK_PRIVATE ${perf_deps} ${OPENCV_MODULE_${the_module}_DEPS} ${OPENCV_LINKER_LIBS} ${OPENCV_PERF_${the_module}_DEPS})
|
||||
ocv_target_link_libraries(${the_target} PRIVATE ${perf_deps} ${OPENCV_MODULE_${the_module}_DEPS} ${OPENCV_LINKER_LIBS} ${OPENCV_PERF_${the_module}_DEPS})
|
||||
add_dependencies(opencv_perf_tests ${the_target})
|
||||
|
||||
set_target_properties(${the_target} PROPERTIES LABELS "${OPENCV_MODULE_${the_module}_LABEL};PerfTest")
|
||||
@@ -1227,7 +1230,7 @@ function(ocv_add_accuracy_tests)
|
||||
if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/test")
|
||||
ocv_target_include_directories(${the_target} "${CMAKE_CURRENT_BINARY_DIR}/test")
|
||||
endif()
|
||||
ocv_target_link_libraries(${the_target} LINK_PRIVATE ${test_deps} ${OPENCV_MODULE_${the_module}_DEPS} ${OPENCV_LINKER_LIBS} ${OPENCV_TEST_${the_module}_DEPS})
|
||||
ocv_target_link_libraries(${the_target} PRIVATE ${test_deps} ${OPENCV_MODULE_${the_module}_DEPS} ${OPENCV_LINKER_LIBS} ${OPENCV_TEST_${the_module}_DEPS})
|
||||
add_dependencies(opencv_tests ${the_target})
|
||||
|
||||
set_target_properties(${the_target} PROPERTIES LABELS "${OPENCV_MODULE_${the_module}_LABEL};AccuracyTest")
|
||||
@@ -1288,7 +1291,7 @@ function(ocv_add_samples)
|
||||
|
||||
ocv_add_executable(${the_target} "${source}")
|
||||
ocv_target_include_modules(${the_target} ${samples_deps})
|
||||
ocv_target_link_libraries(${the_target} LINK_PRIVATE ${samples_deps})
|
||||
ocv_target_link_libraries(${the_target} PRIVATE ${samples_deps})
|
||||
|
||||
set_target_properties(${the_target} PROPERTIES
|
||||
PROJECT_LABEL "(sample) ${name}"
|
||||
|
||||
@@ -125,11 +125,11 @@ MACRO(_PCH_GET_COMPILE_COMMAND out_command _input _output)
|
||||
STRING(REGEX REPLACE "^ +" "" pchsupport_compiler_cxx_arg1 ${CMAKE_CXX_COMPILER_ARG1})
|
||||
|
||||
SET(${out_command}
|
||||
${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input}
|
||||
${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} -x c++-header -o ${_output} -c ${_input}
|
||||
)
|
||||
ELSE(CMAKE_CXX_COMPILER_ARG1)
|
||||
SET(${out_command}
|
||||
${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input}
|
||||
${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} -c ${_input}
|
||||
)
|
||||
ENDIF(CMAKE_CXX_COMPILER_ARG1)
|
||||
ELSE()
|
||||
|
||||
+46
-3
@@ -100,6 +100,30 @@ macro(ocv_update VAR)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(_ocv_access_removed_variable VAR ACCESS)
|
||||
if(ACCESS STREQUAL "MODIFIED_ACCESS")
|
||||
set(OPENCV_SUPPRESS_MESSAGE_REMOVED_VARIABLE_${VAR} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(ACCESS MATCHES "UNKNOWN_.*"
|
||||
AND NOT OPENCV_SUPPRESS_MESSAGE_REMOVED_VARIABLE
|
||||
AND NOT OPENCV_SUPPRESS_MESSAGE_REMOVED_VARIABLE_${VAR}
|
||||
)
|
||||
message(WARNING "OpenCV: Variable has been removed from CMake scripts: ${VAR}")
|
||||
set(OPENCV_SUPPRESS_MESSAGE_REMOVED_VARIABLE_${VAR} 1 PARENT_SCOPE) # suppress similar messages
|
||||
endif()
|
||||
endfunction()
|
||||
macro(ocv_declare_removed_variable VAR)
|
||||
if(NOT DEFINED ${VAR}) # don't hit external variables
|
||||
variable_watch(${VAR} _ocv_access_removed_variable)
|
||||
endif()
|
||||
endmacro()
|
||||
macro(ocv_declare_removed_variables)
|
||||
foreach(_var ${ARGN})
|
||||
ocv_declare_removed_variable(${_var})
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
# Search packages for the host system instead of packages for the target system
|
||||
# in case of cross compilation these macros should be defined by the toolchain file
|
||||
if(NOT COMMAND find_host_package)
|
||||
@@ -288,9 +312,22 @@ function(ocv_append_target_property target prop)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if(DEFINED OPENCV_DEPENDANT_TARGETS_LIST)
|
||||
foreach(v ${OPENCV_DEPENDANT_TARGETS_LIST})
|
||||
unset(${v} CACHE)
|
||||
endforeach()
|
||||
unset(OPENCV_DEPENDANT_TARGETS_LIST CACHE)
|
||||
endif()
|
||||
|
||||
function(ocv_append_dependant_targets target)
|
||||
#ocv_debug_message("ocv_append_dependant_targets(${target} ${ARGN})")
|
||||
_ocv_fix_target(target)
|
||||
list(FIND OPENCV_DEPENDANT_TARGETS_LIST "OPENCV_DEPENDANT_TARGETS_${target}" __id)
|
||||
if(__id EQUAL -1)
|
||||
list(APPEND OPENCV_DEPENDANT_TARGETS_LIST "OPENCV_DEPENDANT_TARGETS_${target}")
|
||||
list(SORT OPENCV_DEPENDANT_TARGETS_LIST)
|
||||
set(OPENCV_DEPENDANT_TARGETS_LIST "${OPENCV_DEPENDANT_TARGETS_LIST}" CACHE INTERNAL "")
|
||||
endif()
|
||||
set(OPENCV_DEPENDANT_TARGETS_${target} "${OPENCV_DEPENDANT_TARGETS_${target}};${ARGN}" CACHE INTERNAL "" FORCE)
|
||||
endfunction()
|
||||
|
||||
@@ -364,6 +401,7 @@ macro(ocv_clear_vars)
|
||||
endmacro()
|
||||
|
||||
set(OCV_COMPILER_FAIL_REGEX
|
||||
"argument '.*' is not valid" # GCC 9+
|
||||
"command line option .* is valid for .* but not for C\\+\\+" # GNU
|
||||
"command line option .* is valid for .* but not for C" # GNU
|
||||
"unrecognized .*option" # GNU
|
||||
@@ -1402,12 +1440,14 @@ endmacro()
|
||||
function(ocv_target_link_libraries target)
|
||||
set(LINK_DEPS ${ARGN})
|
||||
_ocv_fix_target(target)
|
||||
set(LINK_MODE "LINK_PRIVATE")
|
||||
set(LINK_MODE "PRIVATE")
|
||||
set(LINK_PENDING "")
|
||||
foreach(dep ${LINK_DEPS})
|
||||
if(" ${dep}" STREQUAL " ${target}")
|
||||
# prevent "link to itself" warning (world problem)
|
||||
elseif(" ${dep}" STREQUAL " LINK_PRIVATE" OR " ${dep}" STREQUAL "LINK_PUBLIC")
|
||||
elseif(" ${dep}" STREQUAL " LINK_PRIVATE" OR " ${dep}" STREQUAL " LINK_PUBLIC" # deprecated
|
||||
OR " ${dep}" STREQUAL " PRIVATE" OR " ${dep}" STREQUAL " PUBLIC" OR " ${dep}" STREQUAL " INTERFACE"
|
||||
)
|
||||
if(NOT LINK_PENDING STREQUAL "")
|
||||
__ocv_push_target_link_libraries(${LINK_MODE} ${LINK_PENDING})
|
||||
set(LINK_PENDING "")
|
||||
@@ -1546,7 +1586,10 @@ macro(ocv_get_all_libs _modules _extra _3rdparty)
|
||||
endif()
|
||||
if (TARGET ${dep})
|
||||
get_target_property(_type ${dep} TYPE)
|
||||
if(_type STREQUAL "STATIC_LIBRARY" AND BUILD_SHARED_LIBS OR _type STREQUAL "INTERFACE_LIBRARY")
|
||||
if((_type STREQUAL "STATIC_LIBRARY" AND BUILD_SHARED_LIBS)
|
||||
OR _type STREQUAL "INTERFACE_LIBRARY"
|
||||
OR DEFINED OPENCV_MODULE_${dep}_LOCATION # OpenCV modules
|
||||
)
|
||||
# nothing
|
||||
else()
|
||||
get_target_property(_output ${dep} IMPORTED_LOCATION)
|
||||
|
||||
@@ -194,7 +194,7 @@ macro(add_android_project target path)
|
||||
add_library(${JNI_LIB_NAME} SHARED ${android_proj_jni_files})
|
||||
ocv_target_include_modules_recurse(${JNI_LIB_NAME} ${android_proj_NATIVE_DEPS})
|
||||
ocv_target_include_directories(${JNI_LIB_NAME} "${path}/jni")
|
||||
ocv_target_link_libraries(${JNI_LIB_NAME} LINK_PRIVATE ${OPENCV_LINKER_LIBS} ${android_proj_NATIVE_DEPS})
|
||||
ocv_target_link_libraries(${JNI_LIB_NAME} PRIVATE ${OPENCV_LINKER_LIBS} ${android_proj_NATIVE_DEPS})
|
||||
|
||||
set_target_properties(${JNI_LIB_NAME} PROPERTIES
|
||||
OUTPUT_NAME "${JNI_LIB_NAME}"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined _WIN32 && defined(_M_ARM)
|
||||
#if defined _WIN32 && (defined(_M_ARM) || defined(_M_ARM64))
|
||||
# include <Intrin.h>
|
||||
# include <arm_neon.h>
|
||||
# define CV_NEON 1
|
||||
@@ -9,6 +9,10 @@
|
||||
# define CV_NEON 1
|
||||
#endif
|
||||
|
||||
// MSVC 2019 bug. Details: https://github.com/opencv/opencv/pull/16027
|
||||
void test_aliased_type(const uint8x16_t& a) { }
|
||||
void test_aliased_type(const int8x16_t& a) { }
|
||||
|
||||
#if defined CV_NEON
|
||||
int test()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/OpenCV_WinRT.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/OpenCV-WinRT.cmake")
|
||||
|
||||
# Adding additional using directory for WindowsPhone 8.0 to get Windows.winmd properly
|
||||
if(WINRT_8_0)
|
||||
|
||||
@@ -1 +1 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/OpenCV_WinRT.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/OpenCV-WinRT.cmake")
|
||||
|
||||
@@ -84,17 +84,31 @@ endfunction()
|
||||
|
||||
get_filename_component(OpenCV_CONFIG_PATH "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
|
||||
|
||||
if((NOT DEFINED CMAKE_SYSTEM_PROCESSOR OR CMAKE_SYSTEM_PROCESSOR STREQUAL "")
|
||||
AND NOT OPENCV_SUPPRESS_MESSAGE_MISSING_CMAKE_SYSTEM_PROCESSOR)
|
||||
message(WARNING "OpenCV: CMAKE_SYSTEM_PROCESSOR is not defined. Perhaps CMake toolchain is broken")
|
||||
endif()
|
||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P
|
||||
AND NOT OPENCV_SUPPRESS_MESSAGE_MISSING_CMAKE_SIZEOF_VOID_P)
|
||||
message(WARNING "OpenCV: CMAKE_SIZEOF_VOID_P is not defined. Perhaps CMake toolchain is broken")
|
||||
endif()
|
||||
|
||||
if(DEFINED OpenCV_ARCH AND DEFINED OpenCV_RUNTIME)
|
||||
# custom overridden values
|
||||
elseif(MSVC)
|
||||
if(CMAKE_CL_64)
|
||||
set(OpenCV_ARCH x64)
|
||||
elseif((CMAKE_GENERATOR MATCHES "ARM") OR ("${arch_hint}" STREQUAL "ARM") OR (CMAKE_VS_EFFECTIVE_PLATFORMS MATCHES "ARM|arm"))
|
||||
# see Modules/CmakeGenericSystem.cmake
|
||||
set(OpenCV_ARCH ARM)
|
||||
# see Modules/CMakeGenericSystem.cmake
|
||||
if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
|
||||
set(OpenCV_ARCH "x64")
|
||||
elseif("${CMAKE_GENERATOR_PLATFORM}" MATCHES "ARM64")
|
||||
set(OpenCV_ARCH "ARM64")
|
||||
elseif("${CMAKE_GENERATOR}" MATCHES "ARM")
|
||||
set(OpenCV_ARCH "ARM")
|
||||
elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
set(OpenCV_ARCH "x64")
|
||||
else()
|
||||
set(OpenCV_ARCH x86)
|
||||
endif()
|
||||
|
||||
if(MSVC_VERSION EQUAL 1400)
|
||||
set(OpenCV_RUNTIME vc8)
|
||||
elseif(MSVC_VERSION EQUAL 1500)
|
||||
@@ -127,11 +141,7 @@ elseif(MSVC)
|
||||
elseif(MINGW)
|
||||
set(OpenCV_RUNTIME mingw)
|
||||
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpmachine
|
||||
OUTPUT_VARIABLE OPENCV_GCC_TARGET_MACHINE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(OPENCV_GCC_TARGET_MACHINE MATCHES "amd64|x86_64|AMD64")
|
||||
set(MINGW64 1)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*")
|
||||
set(OpenCV_ARCH x64)
|
||||
else()
|
||||
set(OpenCV_ARCH x86)
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
<skip_headers>
|
||||
opencv2/core/hal/intrin*
|
||||
opencv2/core/hal/*macros.*
|
||||
opencv2/core/hal/*.impl.*
|
||||
opencv2/core/cuda*
|
||||
opencv2/core/opencl*
|
||||
opencv2/core/private*
|
||||
|
||||
+20
-2
@@ -157,9 +157,27 @@ if(DOXYGEN_FOUND)
|
||||
list(APPEND CMAKE_DOXYGEN_HTML_FILES "${CMAKE_CURRENT_SOURCE_DIR}/tutorial-utils.js")
|
||||
string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_HTML_FILES "${CMAKE_DOXYGEN_HTML_FILES}")
|
||||
|
||||
set(OPENCV_DOCS_DOT_PATH "" CACHE PATH "Doxygen/DOT_PATH value")
|
||||
set(CMAKECONFIG_DOT_PATH "${OPENCV_DOCS_DOT_PATH}")
|
||||
|
||||
set(OPENCV_DOCS_HAVE_DOT "NO" CACHE BOOL "Doxygen: build extra diagrams")
|
||||
set(CMAKECONFIG_HAVE_DOT "${OPENCV_DOCS_HAVE_DOT}")
|
||||
|
||||
# 'png' is good enough for compatibility (but requires +50% storage space)
|
||||
set(OPENCV_DOCS_DOT_IMAGE_FORMAT "svg" CACHE STRING "Doxygen/DOT_IMAGE_FORMAT value")
|
||||
set(CMAKECONFIG_DOT_IMAGE_FORMAT "${OPENCV_DOCS_DOT_IMAGE_FORMAT}")
|
||||
|
||||
# Doxygen 1.8.16 fix: https://github.com/doxygen/doxygen/pull/6870
|
||||
# NO is needed here: https://github.com/opencv/opencv/pull/16039
|
||||
set(OPENCV_DOCS_INTERACTIVE_SVG "NO" CACHE BOOL "Doxygen/INTERACTIVE_SVG value")
|
||||
set(CMAKECONFIG_INTERACTIVE_SVG "${OPENCV_DOCS_INTERACTIVE_SVG}")
|
||||
|
||||
set(OPENCV_DOCS_DOXYFILE_IN "Doxyfile.in" CACHE PATH "Doxygen configuration template file (Doxyfile.in)")
|
||||
set(OPENCV_DOCS_DOXYGEN_LAYOUT "DoxygenLayout.xml" CACHE PATH "Doxygen layout file (.xml)")
|
||||
|
||||
# writing file
|
||||
configure_file(DoxygenLayout.xml DoxygenLayout.xml @ONLY)
|
||||
configure_file(Doxyfile.in ${doxyfile} @ONLY)
|
||||
configure_file("${OPENCV_DOCS_DOXYGEN_LAYOUT}" DoxygenLayout.xml @ONLY)
|
||||
configure_file("${OPENCV_DOCS_DOXYFILE_IN}" ${doxyfile} @ONLY)
|
||||
configure_file(root.markdown.in ${rootfile} @ONLY)
|
||||
|
||||
# js tutorial assets
|
||||
|
||||
+4
-4
@@ -264,7 +264,7 @@ EXTERNAL_PAGES = YES
|
||||
CLASS_DIAGRAMS = YES
|
||||
DIA_PATH =
|
||||
HIDE_UNDOC_RELATIONS = NO
|
||||
HAVE_DOT = NO
|
||||
HAVE_DOT = @CMAKECONFIG_HAVE_DOT@
|
||||
DOT_NUM_THREADS = 0
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_FONTSIZE = 10
|
||||
@@ -281,9 +281,9 @@ CALL_GRAPH = YES
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = svg
|
||||
INTERACTIVE_SVG = YES
|
||||
DOT_PATH =
|
||||
DOT_IMAGE_FORMAT = @CMAKECONFIG_DOT_IMAGE_FORMAT@
|
||||
INTERACTIVE_SVG = @CMAKECONFIG_INTERACTIVE_SVG@
|
||||
DOT_PATH = @CMAKECONFIG_DOT_PATH@
|
||||
DOTFILE_DIRS =
|
||||
MSCFILE_DIRS =
|
||||
DIAFILE_DIRS =
|
||||
|
||||
@@ -27,7 +27,7 @@ src1.delete(); src2.delete(); dst.delete(); mask.delete();
|
||||
Image Subtraction
|
||||
--------------
|
||||
|
||||
You can subtract two images by OpenCV function, cv.subtract(). res = img1 - img2. Both images should be of same depth and type.
|
||||
You can subtract two images by OpenCV function, cv.subtract(). res = img1 - img2. Both images should be of same depth and type. Note that when used with RGBA images, the alpha channel is also subtracted.
|
||||
|
||||
For example, consider below sample:
|
||||
@code{.js}
|
||||
@@ -59,4 +59,4 @@ Try it
|
||||
<iframe src="../../js_image_arithmetics_bitwise.html" width="100%"
|
||||
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
|
||||
</iframe>
|
||||
\endhtmlonly
|
||||
\endhtmlonly
|
||||
|
||||
@@ -36,7 +36,7 @@ let x = document.getElementById('myRange');
|
||||
@endcode
|
||||
|
||||
As a trackbar, the range element need a trackbar name, the default value, minimum value, maximum value,
|
||||
step and the callback function which is executed everytime trackbar value changes. The callback function
|
||||
step and the callback function which is executed every time trackbar value changes. The callback function
|
||||
always has a default argument, which is the trackbar position. Additionally, a text element to display the
|
||||
trackbar value is fine. In our case, we can create the trackbar as below:
|
||||
@code{.html}
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
Using OpenCV.js In Node.js {#tutorial_js_nodejs}
|
||||
==========================
|
||||
|
||||
Goals
|
||||
-----
|
||||
|
||||
In this tutorial, you will learn:
|
||||
|
||||
- Use OpenCV.js in a [Node.js](https://nodejs.org) application.
|
||||
- Load images with [jimp](https://www.npmjs.com/package/jimp) in order to use them with OpenCV.js.
|
||||
- Using [jsdom](https://www.npmjs.com/package/canvas) and [node-canvas](https://www.npmjs.com/package/canvas) to support `cv.imread()`, `cv.imshow()`
|
||||
- The basics of [emscripten](https://emscripten.org/) APIs, like [Module](https://emscripten.org/docs/api_reference/module.html) and [File System](https://emscripten.org/docs/api_reference/Filesystem-API.html) on which OpenCV.js is based.
|
||||
- Learn Node.js basics. Although this tutorial assumes the user knows JavaScript, experience with Node.js is not required.
|
||||
|
||||
@note Besides giving instructions to run OpenCV.js in Node.js, another objective of this tutorial is to introduce users to the basics of [emscripten](https://emscripten.org/) APIs, like [Module](https://emscripten.org/docs/api_reference/module.html) and [File System](https://emscripten.org/docs/api_reference/Filesystem-API.html) and also Node.js.
|
||||
|
||||
|
||||
Minimal example
|
||||
-----
|
||||
|
||||
Create a file `example1.js` with the following content:
|
||||
|
||||
@code{.js}
|
||||
// Define a global variable 'Module' with a method 'onRuntimeInitialized':
|
||||
Module = {
|
||||
onRuntimeInitialized() {
|
||||
// this is our application:
|
||||
console.log(cv.getBuildInformation())
|
||||
}
|
||||
}
|
||||
// Load 'opencv.js' assigning the value to the global variable 'cv'
|
||||
cv = require('./opencv.js')
|
||||
@endcode
|
||||
|
||||
### Execute it ###
|
||||
|
||||
- Save the file as `example1.js`.
|
||||
- Make sure the file `opencv.js` is in the same folder.
|
||||
- Make sure [Node.js](https://nodejs.org) is installed on your system.
|
||||
|
||||
The following command should print OpenCV build information:
|
||||
|
||||
@code{.bash}
|
||||
node example1.js
|
||||
@endcode
|
||||
|
||||
### What just happened? ###
|
||||
|
||||
* **In the first statement**:, by defining a global variable named 'Module', emscripten will call `Module.onRuntimeInitialized()` when the library is ready to use. Our program is in that method and uses the global variable `cv` just like in the browser.
|
||||
* The statement **"cv = require('./opencv.js')"** requires the file `opencv.js` and assign the return value to the global variable `cv`.
|
||||
`require()` which is a Node.js API, is used to load modules and files.
|
||||
In this case we load the file `opencv.js` form the current folder, and, as said previously emscripten will call `Module.onRuntimeInitialized()` when its ready.
|
||||
* See [emscripten Module API](https://emscripten.org/docs/api_reference/module.html) for more details.
|
||||
|
||||
|
||||
Working with images
|
||||
-----
|
||||
|
||||
OpenCV.js doesn't support image formats so we can't load png or jpeg images directly. In the browser it uses the HTML DOM (like HTMLCanvasElement and HTMLImageElement to decode and decode images). In node.js we will need to use a library for this.
|
||||
|
||||
In this example we use [jimp](https://www.npmjs.com/package/jimp), which supports common image formats and is pretty easy to use.
|
||||
|
||||
### Example setup ###
|
||||
|
||||
Execute the following commands to create a new node.js package and install [jimp](https://www.npmjs.com/package/jimp) dependency:
|
||||
|
||||
@code{.bash}
|
||||
mkdir project1
|
||||
cd project1
|
||||
npm init -y
|
||||
npm install jimp
|
||||
@endcode
|
||||
|
||||
### The example ###
|
||||
|
||||
@code{.js}
|
||||
const Jimp = require('jimp');
|
||||
|
||||
async function onRuntimeInitialized(){
|
||||
|
||||
// load local image file with jimp. It supports jpg, png, bmp, tiff and gif:
|
||||
var jimpSrc = await Jimp.read('./lena.jpg');
|
||||
|
||||
// `jimpImage.bitmap` property has the decoded ImageData that we can use to create a cv:Mat
|
||||
var src = cv.matFromImageData(jimpSrc.bitmap);
|
||||
|
||||
// following lines is copy&paste of opencv.js dilate tutorial:
|
||||
let dst = new cv.Mat();
|
||||
let M = cv.Mat.ones(5, 5, cv.CV_8U);
|
||||
let anchor = new cv.Point(-1, -1);
|
||||
cv.dilate(src, dst, M, anchor, 1, cv.BORDER_CONSTANT, cv.morphologyDefaultBorderValue());
|
||||
|
||||
// Now that we are finish, we want to write `dst` to file `output.png`. For this we create a `Jimp`
|
||||
// image which accepts the image data as a [`Buffer`](https://nodejs.org/docs/latest-v10.x/api/buffer.html).
|
||||
// `write('output.png')` will write it to disk and Jimp infers the output format from given file name:
|
||||
new Jimp({
|
||||
width: dst.cols,
|
||||
height: dst.rows,
|
||||
data: Buffer.from(dst.data)
|
||||
})
|
||||
.write('output.png');
|
||||
|
||||
src.delete();
|
||||
dst.delete();
|
||||
}
|
||||
|
||||
// Finally, load the open.js as before. The function `onRuntimeInitialized` contains our program.
|
||||
Module = {
|
||||
onRuntimeInitialized
|
||||
};
|
||||
cv = require('./opencv.js');
|
||||
@endcode
|
||||
|
||||
### Execute it ###
|
||||
|
||||
- Save the file as `exampleNodeJimp.js`.
|
||||
- Make sure a sample image `lena.jpg` exists in the current directory.
|
||||
|
||||
The following command should generate the file `output.png`:
|
||||
|
||||
@code{.bash}
|
||||
node exampleNodeJimp.js
|
||||
@endcode
|
||||
|
||||
|
||||
Emulating HTML DOM and canvas
|
||||
-----
|
||||
|
||||
As you might already seen, the rest of the examples use functions like `cv.imread()`, `cv.imshow()` to read and write images. Unfortunately as mentioned they won't work on Node.js since there is no HTML DOM.
|
||||
|
||||
In this section, you will learn how to use [jsdom](https://www.npmjs.com/package/canvas) and [node-canvas](https://www.npmjs.com/package/canvas) to emulate the HTML DOM on Node.js so those functions work.
|
||||
|
||||
### Example setup ###
|
||||
|
||||
As before, we create a Node.js project and install the dependencies we need:
|
||||
|
||||
@code{.bash}
|
||||
mkdir project2
|
||||
cd project2
|
||||
npm init -y
|
||||
npm install canvas jsdom
|
||||
@endcode
|
||||
|
||||
### The example ###
|
||||
|
||||
@code{.js}
|
||||
const { Canvas, createCanvas, Image, ImageData, loadImage } = require('canvas');
|
||||
const { JSDOM } = require('jsdom');
|
||||
const { writeFileSync } = require('fs');
|
||||
|
||||
// This is our program. This time we use JavaScript async / await and promises to handle asynchronicity.
|
||||
(async () => {
|
||||
|
||||
// before loading opencv.js we emulate a minimal HTML DOM. See the function declaration below.
|
||||
installDOM();
|
||||
|
||||
await loadOpenCV();
|
||||
|
||||
// using node-canvas, we an image file to an object compatible with HTML DOM Image and therefore with cv.imread()
|
||||
const image = await loadImage('./lena.jpg');
|
||||
|
||||
const src = cv.imread(image);
|
||||
const dst = new cv.Mat();
|
||||
const M = cv.Mat.ones(5, 5, cv.CV_8U);
|
||||
const anchor = new cv.Point(-1, -1);
|
||||
cv.dilate(src, dst, M, anchor, 1, cv.BORDER_CONSTANT, cv.morphologyDefaultBorderValue());
|
||||
|
||||
// we create an object compatible HTMLCanvasElement
|
||||
const canvas = createCanvas(300, 300);
|
||||
cv.imshow(canvas, dst);
|
||||
writeFileSync('output.jpg', canvas.toBuffer('image/jpeg'));
|
||||
src.delete();
|
||||
dst.delete();
|
||||
})();
|
||||
|
||||
// Load opencv.js just like before but using Promise instead of callbacks:
|
||||
function loadOpenCV() {
|
||||
return new Promise(resolve => {
|
||||
global.Module = {
|
||||
onRuntimeInitialized: resolve
|
||||
};
|
||||
global.cv = require('./opencv.js');
|
||||
});
|
||||
}
|
||||
|
||||
// Using jsdom and node-canvas we define some global variables to emulate HTML DOM.
|
||||
// Although a complete emulation can be archived, here we only define those globals used
|
||||
// by cv.imread() and cv.imshow().
|
||||
function installDOM() {
|
||||
const dom = new JSDOM();
|
||||
global.document = dom.window.document;
|
||||
|
||||
// The rest enables DOM image and canvas and is provided by node-canvas
|
||||
global.Image = Image;
|
||||
global.HTMLCanvasElement = Canvas;
|
||||
global.ImageData = ImageData;
|
||||
global.HTMLImageElement = Image;
|
||||
}
|
||||
@endcode
|
||||
|
||||
### Execute it ###
|
||||
|
||||
- Save the file as `exampleNodeCanvas.js`.
|
||||
- Make sure a sample image `lena.jpg` exists in the current directory.
|
||||
|
||||
The following command should generate the file `output.jpg`:
|
||||
|
||||
@code{.bash}
|
||||
node exampleNodeCanvas.js
|
||||
@endcode
|
||||
|
||||
|
||||
Dealing with files
|
||||
-----
|
||||
|
||||
In this tutorial you will learn how to configure emscripten so it uses the local filesystem for file operations instead of using memory. Also it tries to describe how [files are supported by emscripten applications](https://emscripten.org/docs/api_reference/Filesystem-API.html)
|
||||
|
||||
Accessing the emscripten filesystem is often needed in OpenCV applications for example to load machine learning models such as the ones used in @ref tutorial_dnn_googlenet and @ref tutorial_dnn_javascript.
|
||||
|
||||
### Example setup ###
|
||||
|
||||
Before the example, is worth consider first how files are handled in emscripten applications such as OpenCV.js. Remember that OpenCV library is written in C++ and the file opencv.js is just that C++ code being translated to JavaScript or WebAssembly by emscripten C++ compiler.
|
||||
|
||||
These C++ sources use standard APIs to access the filesystem and the implementation often ends up in system calls that read a file in the hard drive. Since JavaScript applications in the browser don't have access to the local filesystem, [emscripten emulates a standard filesystem](https://emscripten.org/docs/api_reference/Filesystem-API.html) so compiled C++ code works out of the box.
|
||||
|
||||
In the browser, this filesystem is emulated in memory while in Node.js there's also the possibility of using the local filesystem directly. This is often preferable since there's no need of copy file's content in memory. This section is explains how to do do just that, this is, configuring emscripten so files are accessed directly from our local filesystem and relative paths match files relative to the current local directory as expected.
|
||||
|
||||
### The example ###
|
||||
|
||||
The following is an adaptation of @ref tutorial_js_face_detection.
|
||||
|
||||
@code{.js}
|
||||
const { Canvas, createCanvas, Image, ImageData, loadImage } = require('canvas');
|
||||
const { JSDOM } = require('jsdom');
|
||||
const { writeFileSync, readFileSync } = require('fs');
|
||||
|
||||
(async () => {
|
||||
await loadOpenCV();
|
||||
|
||||
const image = await loadImage('lena.jpg');
|
||||
const src = cv.imread(image);
|
||||
let gray = new cv.Mat();
|
||||
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
|
||||
let faces = new cv.RectVector();
|
||||
let eyes = new cv.RectVector();
|
||||
let faceCascade = new cv.CascadeClassifier();
|
||||
let eyeCascade = new cv.CascadeClassifier();
|
||||
|
||||
// Load pre-trained classifier files. Notice how we reference local files using relative paths just
|
||||
// like we normally would do
|
||||
faceCascade.load('./haarcascade_frontalface_default.xml');
|
||||
eyeCascade.load('./haarcascade_eye.xml');
|
||||
|
||||
let mSize = new cv.Size(0, 0);
|
||||
faceCascade.detectMultiScale(gray, faces, 1.1, 3, 0, mSize, mSize);
|
||||
for (let i = 0; i < faces.size(); ++i) {
|
||||
let roiGray = gray.roi(faces.get(i));
|
||||
let roiSrc = src.roi(faces.get(i));
|
||||
let point1 = new cv.Point(faces.get(i).x, faces.get(i).y);
|
||||
let point2 = new cv.Point(faces.get(i).x + faces.get(i).width, faces.get(i).y + faces.get(i).height);
|
||||
cv.rectangle(src, point1, point2, [255, 0, 0, 255]);
|
||||
eyeCascade.detectMultiScale(roiGray, eyes);
|
||||
for (let j = 0; j < eyes.size(); ++j) {
|
||||
let point1 = new cv.Point(eyes.get(j).x, eyes.get(j).y);
|
||||
let point2 = new cv.Point(eyes.get(j).x + eyes.get(j).width, eyes.get(j).y + eyes.get(j).height);
|
||||
cv.rectangle(roiSrc, point1, point2, [0, 0, 255, 255]);
|
||||
}
|
||||
roiGray.delete();
|
||||
roiSrc.delete();
|
||||
}
|
||||
|
||||
const canvas = createCanvas(image.width, image.height);
|
||||
cv.imshow(canvas, src);
|
||||
writeFileSync('output3.jpg', canvas.toBuffer('image/jpeg'));
|
||||
src.delete(); gray.delete(); faceCascade.delete(); eyeCascade.delete(); faces.delete(); eyes.delete()
|
||||
})();
|
||||
|
||||
/**
|
||||
* Loads opencv.js.
|
||||
*
|
||||
* Installs HTML Canvas emulation to support `cv.imread()` and `cv.imshow`
|
||||
*
|
||||
* Mounts given local folder `localRootDir` in emscripten filesystem folder `rootDir`. By default it will mount the local current directory in emscripten `/work` directory. This means that `/work/foo.txt` will be resolved to the local file `./foo.txt`
|
||||
* @param {string} rootDir The directory in emscripten filesystem in which the local filesystem will be mount.
|
||||
* @param {string} localRootDir The local directory to mount in emscripten filesystem.
|
||||
* @returns {Promise} resolved when the library is ready to use.
|
||||
*/
|
||||
function loadOpenCV(rootDir = '/work', localRootDir = process.cwd()) {
|
||||
if(global.Module && global.Module.onRuntimeInitialized && global.cv && global.cv.imread) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
installDOM()
|
||||
global.Module = {
|
||||
onRuntimeInitialized() {
|
||||
// We change emscripten current work directory to 'rootDir' so relative paths are resolved
|
||||
// relative to the current local folder, as expected
|
||||
cv.FS.chdir(rootDir)
|
||||
resolve()
|
||||
},
|
||||
preRun() {
|
||||
// preRun() is another callback like onRuntimeInitialized() but is called just before the
|
||||
// library code runs. Here we mount a local folder in emscripten filesystem and we want to
|
||||
// do this before the library is executed so the filesystem is accessible from the start
|
||||
const FS = global.Module.FS
|
||||
// create rootDir if it doesn't exists
|
||||
if(!FS.analyzePath(rootDir).exists) {
|
||||
FS.mkdir(rootDir);
|
||||
}
|
||||
// create localRootFolder if it doesn't exists
|
||||
if(!existsSync(localRootDir)) {
|
||||
mkdirSync(localRootDir, { recursive: true});
|
||||
}
|
||||
// FS.mount() is similar to Linux/POSIX mount operation. It basically mounts an external
|
||||
// filesystem with given format, in given current filesystem directory.
|
||||
FS.mount(FS.filesystems.NODEFS, { root: localRootDir}, rootDir);
|
||||
}
|
||||
};
|
||||
global.cv = require('./opencv.js')
|
||||
});
|
||||
}
|
||||
|
||||
function installDOM(){
|
||||
const dom = new JSDOM();
|
||||
global.document = dom.window.document;
|
||||
global.Image = Image;
|
||||
global.HTMLCanvasElement = Canvas;
|
||||
global.ImageData = ImageData;
|
||||
global.HTMLImageElement = Image;
|
||||
}
|
||||
@endcode
|
||||
|
||||
### Execute it ###
|
||||
|
||||
- Save the file as `exampleNodeCanvasData.js`.
|
||||
- Make sure the files `aarcascade_frontalface_default.xml` and `haarcascade_eye.xml` are present in project's directory. They can be obtained from [OpenCV sources](https://github.com/opencv/opencv/tree/master/data/haarcascades).
|
||||
- Make sure a sample image file `lena.jpg` exists in project's directory. It should display people's faces for this example to make sense. The following image is known to work:
|
||||
|
||||

|
||||
|
||||
The following command should generate the file `output3.jpg`:
|
||||
|
||||
@code{.bash}
|
||||
node exampleNodeCanvasData.js
|
||||
@endcode
|
||||
@@ -91,21 +91,60 @@ Building OpenCV.js from Source
|
||||
python ./platforms/js/build_js.py build_js --build_test
|
||||
@endcode
|
||||
|
||||
To run tests, launch a local web server in \<build_dir\>/bin folder. For example, node http-server which serves on `localhost:8080`.
|
||||
Running OpenCV.js Tests
|
||||
---------------------------------------
|
||||
|
||||
Navigate the web browser to `http://localhost:8080/tests.html`, which runs the unit tests automatically.
|
||||
Remember to launch the build command passing `--build_test` as mentioned previously. This will generate test source code ready to run together with `opencv.js` file in `build_js/bin`
|
||||
|
||||
You can also run tests using Node.js.
|
||||
### Manually in your browser
|
||||
|
||||
For example:
|
||||
@code{.sh}
|
||||
cd bin
|
||||
npm install
|
||||
node tests.js
|
||||
@endcode
|
||||
To run tests, launch a local web server in `\<build_dir\>/bin` folder. For example, node http-server which serves on `localhost:8080`.
|
||||
|
||||
Navigate the web browser to `http://localhost:8080/tests.html`, which runs the unit tests automatically. Command example:
|
||||
|
||||
@code{.sh}
|
||||
npx http-server build_js/bin
|
||||
firefox http://localhost:8080/tests.html
|
||||
@endcode
|
||||
|
||||
@note
|
||||
This snippet and the following require [Node.js](https://nodejs.org) to be installed.
|
||||
|
||||
### Headless with Puppeteer
|
||||
|
||||
Alternatively tests can run with [GoogleChrome/puppeteer](https://github.com/GoogleChrome/puppeteer#readme) which is a version of Google Chrome that runs in the terminal (useful for Continuos integration like travis CI, etc)
|
||||
|
||||
@code{.sh}
|
||||
cd build_js/bin
|
||||
npm install
|
||||
npm install --no-save puppeteer # automatically downloads Chromium package
|
||||
node run_puppeteer.js
|
||||
@endcode
|
||||
|
||||
@note
|
||||
Checkout `node run_puppeteer --help` for more options to debug and reporting.
|
||||
|
||||
@note
|
||||
The command `npm install` only needs to be executed once, since installs the tools dependencies; after that they are ready to use.
|
||||
|
||||
@note
|
||||
Use `PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 npm install --no-save puppeteer` to skip automatic downloading of Chromium.
|
||||
You may specify own Chromium/Chrome binary through `PUPPETEER_EXECUTABLE_PATH=$(which google-chrome)` environment variable.
|
||||
**BEWARE**: Puppeteer is only guaranteed to work with the bundled Chromium, use at your own risk.
|
||||
|
||||
|
||||
### Using Node.js.
|
||||
|
||||
For example:
|
||||
|
||||
@code{.sh}
|
||||
cd build_js/bin
|
||||
npm install
|
||||
node tests.js
|
||||
@endcode
|
||||
|
||||
@note If all tests are failed, then consider using Node.js from 8.x version (`lts/carbon` from `nvm`).
|
||||
|
||||
@note
|
||||
It requires `node` installed in your development environment.
|
||||
|
||||
-# [optional] To build `opencv.js` with threads optimization, append `--threads` option.
|
||||
|
||||
|
||||
@@ -12,3 +12,7 @@ Introduction to OpenCV.js {#tutorial_js_table_of_contents_setup}
|
||||
- @subpage tutorial_js_setup
|
||||
|
||||
Build OpenCV.js from source
|
||||
|
||||
- @subpage tutorial_js_nodejs
|
||||
|
||||
Using OpenCV.js In Node.js
|
||||
@@ -102,6 +102,14 @@
|
||||
publisher = {Elsevier},
|
||||
url = {https://www.cs.bgu.ac.il/~icbv161/wiki.files/Readings/1981-Ballard-Generalizing_the_Hough_Transform_to_Detect_Arbitrary_Shapes.pdf}
|
||||
}
|
||||
@techreport{blanco2010tutorial,
|
||||
title = {A tutorial on SE(3) transformation parameterizations and on-manifold optimization},
|
||||
author = {Blanco, Jose-Luis},
|
||||
institution = {University of Malaga},
|
||||
number = {012010},
|
||||
year = {2010},
|
||||
url = {http://ingmec.ual.es/~jlblanco/papers/jlblanco2010geometry3D_techrep.pdf}
|
||||
}
|
||||
@article{Borgefors86,
|
||||
author = {Borgefors, Gunilla},
|
||||
title = {Distance transformations in digital images},
|
||||
@@ -277,6 +285,12 @@
|
||||
year = {2013},
|
||||
url = {http://ethaneade.com/optimization.pdf}
|
||||
}
|
||||
@misc{Eade17,
|
||||
author = {Eade, Ethan},
|
||||
title = {Lie Groups for 2D and 3D Transformation},
|
||||
year = {2017},
|
||||
url = {http://www.ethaneade.com/lie.pdf}
|
||||
}
|
||||
@inproceedings{EM11,
|
||||
author = {Gastal, Eduardo SL and Oliveira, Manuel M},
|
||||
title = {Domain transform for edge-aware image and video processing},
|
||||
@@ -397,6 +411,14 @@
|
||||
year = {1999},
|
||||
url = {https://pdfs.semanticscholar.org/090d/25f94cb021bdd3400a2f547f989a6a5e07ec.pdf}
|
||||
}
|
||||
@article{Gallego2014ACF,
|
||||
title = {A Compact Formula for the Derivative of a 3-D Rotation in Exponential Coordinates},
|
||||
author = {Guillermo Gallego and Anthony J. Yezzi},
|
||||
journal = {Journal of Mathematical Imaging and Vision},
|
||||
year = {2014},
|
||||
volume = {51},
|
||||
pages = {378-384}
|
||||
}
|
||||
@article{taubin1991,
|
||||
abstract = {The author addresses the problem of parametric representation and estimation of complex planar curves in 2-D surfaces in 3-D, and nonplanar space curves in 3-D. Curves and surfaces can be defined either parametrically or implicitly, with the latter representation used here. A planar curve is the set of zeros of a smooth function of two variables <e1>x</e1>-<e1>y</e1>, a surface is the set of zeros of a smooth function of three variables <e1>x</e1>-<e1>y</e1>-<e1>z</e1>, and a space curve is the intersection of two surfaces, which are the set of zeros of two linearly independent smooth functions of three variables <e1>x</e1>-<e1>y</e1>-<e1>z</e1> For example, the surface of a complex object in 3-D can be represented as a subset of a single implicit surface, with similar results for planar and space curves. It is shown how this unified representation can be used for object recognition, object position estimation, and segmentation of objects into meaningful subobjects, that is, the detection of `interest regions' that are more complex than high curvature regions and, hence, more useful as features for object recognition},
|
||||
author = {Taubin, Gabriel},
|
||||
@@ -915,6 +937,13 @@
|
||||
journal = {Retrieved on August},
|
||||
volume = {6}
|
||||
}
|
||||
@article{Sol2018AML,
|
||||
title = {A micro Lie theory for state estimation in robotics},
|
||||
author = {Joan Sol{\`a} and J{\'e}r{\'e}mie Deray and Dinesh Atchuthan},
|
||||
journal = {ArXiv},
|
||||
year = {2018},
|
||||
volume={abs/1812.01537}
|
||||
}
|
||||
@misc{SteweniusCFS,
|
||||
author = {Stewenius, Henrik},
|
||||
title = {Calibrated Fivepoint solver},
|
||||
|
||||
@@ -8,13 +8,13 @@ Learn to:
|
||||
|
||||
- Access pixel values and modify them
|
||||
- Access image properties
|
||||
- Setting Region of Interest (ROI)
|
||||
- Splitting and Merging images
|
||||
- Set a Region of Interest (ROI)
|
||||
- Split and merge images
|
||||
|
||||
Almost all the operations in this section is mainly related to Numpy rather than OpenCV. A good
|
||||
Almost all the operations in this section are mainly related to Numpy rather than OpenCV. A good
|
||||
knowledge of Numpy is required to write better optimized code with OpenCV.
|
||||
|
||||
*( Examples will be shown in Python terminal since most of them are just single line codes )*
|
||||
*( Examples will be shown in a Python terminal, since most of them are just single lines of code )*
|
||||
|
||||
Accessing and Modifying pixel values
|
||||
------------------------------------
|
||||
@@ -45,15 +45,15 @@ You can modify the pixel values the same way.
|
||||
[255 255 255]
|
||||
@endcode
|
||||
|
||||
**warning**
|
||||
**Warning**
|
||||
|
||||
Numpy is a optimized library for fast array calculations. So simply accessing each and every pixel
|
||||
values and modifying it will be very slow and it is discouraged.
|
||||
Numpy is an optimized library for fast array calculations. So simply accessing each and every pixel
|
||||
value and modifying it will be very slow and it is discouraged.
|
||||
|
||||
@note The above method is normally used for selecting a region of an array, say the first 5 rows
|
||||
and last 3 columns. For individual pixel access, the Numpy array methods, array.item() and
|
||||
array.itemset() are considered better, however they always return a scalar. If you want to access
|
||||
all B,G,R values, you need to call array.item() separately for all.
|
||||
array.itemset() are considered better. They always return a scalar, however, so if you want to access
|
||||
all the B,G,R values, you will need to call array.item() separately for each value.
|
||||
|
||||
Better pixel accessing and editing method :
|
||||
@code{.py}
|
||||
@@ -70,11 +70,10 @@ Better pixel accessing and editing method :
|
||||
Accessing Image Properties
|
||||
--------------------------
|
||||
|
||||
Image properties include number of rows, columns and channels, type of image data, number of pixels
|
||||
etc.
|
||||
Image properties include number of rows, columns, and channels; type of image data; number of pixels; etc.
|
||||
|
||||
The shape of an image is accessed by img.shape. It returns a tuple of number of rows, columns, and channels
|
||||
(if image is color):
|
||||
The shape of an image is accessed by img.shape. It returns a tuple of the number of rows, columns, and channels
|
||||
(if the image is color):
|
||||
@code{.py}
|
||||
>>> print( img.shape )
|
||||
(342, 548, 3)
|
||||
@@ -95,13 +94,13 @@ uint8
|
||||
@endcode
|
||||
|
||||
@note img.dtype is very important while debugging because a large number of errors in OpenCV-Python
|
||||
code is caused by invalid datatype.
|
||||
code are caused by invalid datatype.
|
||||
|
||||
Image ROI
|
||||
---------
|
||||
|
||||
Sometimes, you will have to play with certain region of images. For eye detection in images, first
|
||||
face detection is done all over the image. When a face is obtained, we select the face region alone
|
||||
Sometimes, you will have to play with certain regions of images. For eye detection in images, first
|
||||
face detection is done over the entire image. When a face is obtained, we select the face region alone
|
||||
and search for eyes inside it instead of searching the whole image. It improves accuracy (because eyes
|
||||
are always on faces :D ) and performance (because we search in a small area).
|
||||
|
||||
@@ -118,9 +117,9 @@ Check the results below:
|
||||
Splitting and Merging Image Channels
|
||||
------------------------------------
|
||||
|
||||
Sometimes you will need to work separately on B,G,R channels of image. In this case, you need
|
||||
to split the BGR images to single channels. In other cases, you may need to join these individual
|
||||
channels to a BGR image. You can do it simply by:
|
||||
Sometimes you will need to work separately on the B,G,R channels of an image. In this case, you need
|
||||
to split the BGR image into single channels. In other cases, you may need to join these individual
|
||||
channels to create a BGR image. You can do this simply by:
|
||||
@code{.py}
|
||||
>>> b,g,r = cv.split(img)
|
||||
>>> img = cv.merge((b,g,r))
|
||||
@@ -129,7 +128,7 @@ Or
|
||||
@code
|
||||
>>> b = img[:,:,0]
|
||||
@endcode
|
||||
Suppose you want to set all the red pixels to zero, you do not need to split the channels first.
|
||||
Suppose you want to set all the red pixels to zero - you do not need to split the channels first.
|
||||
Numpy indexing is faster:
|
||||
@code{.py}
|
||||
>>> img[:,:,2] = 0
|
||||
@@ -137,13 +136,13 @@ Numpy indexing is faster:
|
||||
|
||||
**Warning**
|
||||
|
||||
cv.split() is a costly operation (in terms of time). So do it only if you need it. Otherwise go
|
||||
cv.split() is a costly operation (in terms of time). So use it only if necessary. Otherwise go
|
||||
for Numpy indexing.
|
||||
|
||||
Making Borders for Images (Padding)
|
||||
-----------------------------------
|
||||
|
||||
If you want to create a border around the image, something like a photo frame, you can use
|
||||
If you want to create a border around an image, something like a photo frame, you can use
|
||||
**cv.copyMakeBorder()**. But it has more applications for convolution operation, zero
|
||||
padding etc. This function takes following arguments:
|
||||
|
||||
|
||||
@@ -4,21 +4,20 @@ Arithmetic Operations on Images {#tutorial_py_image_arithmetics}
|
||||
Goal
|
||||
----
|
||||
|
||||
- Learn several arithmetic operations on images like addition, subtraction, bitwise operations
|
||||
etc.
|
||||
- You will learn these functions : **cv.add()**, **cv.addWeighted()** etc.
|
||||
- Learn several arithmetic operations on images, like addition, subtraction, bitwise operations, and etc.
|
||||
- Learn these functions: **cv.add()**, **cv.addWeighted()**, etc.
|
||||
|
||||
Image Addition
|
||||
--------------
|
||||
|
||||
You can add two images by OpenCV function, cv.add() or simply by numpy operation,
|
||||
res = img1 + img2. Both images should be of same depth and type, or second image can just be a
|
||||
You can add two images with the OpenCV function, cv.add(), or simply by the numpy operation
|
||||
res = img1 + img2. Both images should be of same depth and type, or the second image can just be a
|
||||
scalar value.
|
||||
|
||||
@note There is a difference between OpenCV addition and Numpy addition. OpenCV addition is a
|
||||
saturated operation while Numpy addition is a modulo operation.
|
||||
|
||||
For example, consider below sample:
|
||||
For example, consider the below sample:
|
||||
@code{.py}
|
||||
>>> x = np.uint8([250])
|
||||
>>> y = np.uint8([10])
|
||||
@@ -29,13 +28,12 @@ For example, consider below sample:
|
||||
>>> print( x+y ) # 250+10 = 260 % 256 = 4
|
||||
[4]
|
||||
@endcode
|
||||
It will be more visible when you add two images. OpenCV function will provide a better result. So
|
||||
always better stick to OpenCV functions.
|
||||
This will be more visible when you add two images. Stick with OpenCV functions, because they will provide a better result.
|
||||
|
||||
Image Blending
|
||||
--------------
|
||||
|
||||
This is also image addition, but different weights are given to images so that it gives a feeling of
|
||||
This is also image addition, but different weights are given to images in order to give a feeling of
|
||||
blending or transparency. Images are added as per the equation below:
|
||||
|
||||
\f[g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x)\f]
|
||||
@@ -43,8 +41,8 @@ blending or transparency. Images are added as per the equation below:
|
||||
By varying \f$\alpha\f$ from \f$0 \rightarrow 1\f$, you can perform a cool transition between one image to
|
||||
another.
|
||||
|
||||
Here I took two images to blend them together. First image is given a weight of 0.7 and second image
|
||||
is given 0.3. cv.addWeighted() applies following equation on the image.
|
||||
Here I took two images to blend together. The first image is given a weight of 0.7 and the second image
|
||||
is given 0.3. cv.addWeighted() applies the following equation to the image:
|
||||
|
||||
\f[dst = \alpha \cdot img1 + \beta \cdot img2 + \gamma\f]
|
||||
|
||||
@@ -66,14 +64,14 @@ Check the result below:
|
||||
Bitwise Operations
|
||||
------------------
|
||||
|
||||
This includes bitwise AND, OR, NOT and XOR operations. They will be highly useful while extracting
|
||||
This includes the bitwise AND, OR, NOT, and XOR operations. They will be highly useful while extracting
|
||||
any part of the image (as we will see in coming chapters), defining and working with non-rectangular
|
||||
ROI etc. Below we will see an example on how to change a particular region of an image.
|
||||
ROI's, and etc. Below we will see an example of how to change a particular region of an image.
|
||||
|
||||
I want to put OpenCV logo above an image. If I add two images, it will change color. If I blend it,
|
||||
I get an transparent effect. But I want it to be opaque. If it was a rectangular region, I could use
|
||||
ROI as we did in last chapter. But OpenCV logo is a not a rectangular shape. So you can do it with
|
||||
bitwise operations as below:
|
||||
I want to put the OpenCV logo above an image. If I add two images, it will change the color. If I blend them,
|
||||
I get a transparent effect. But I want it to be opaque. If it was a rectangular region, I could use
|
||||
ROI as we did in the last chapter. But the OpenCV logo is a not a rectangular shape. So you can do it with
|
||||
bitwise operations as shown below:
|
||||
@code{.py}
|
||||
# Load two images
|
||||
img1 = cv.imread('messi5.jpg')
|
||||
@@ -81,7 +79,7 @@ img2 = cv.imread('opencv-logo-white.png')
|
||||
|
||||
# I want to put logo on top-left corner, So I create a ROI
|
||||
rows,cols,channels = img2.shape
|
||||
roi = img1[0:rows, 0:cols ]
|
||||
roi = img1[0:rows, 0:cols]
|
||||
|
||||
# Now create a mask of logo and create its inverse mask also
|
||||
img2gray = cv.cvtColor(img2,cv.COLOR_BGR2GRAY)
|
||||
|
||||
@@ -4,28 +4,27 @@ Performance Measurement and Improvement Techniques {#tutorial_py_optimization}
|
||||
Goal
|
||||
----
|
||||
|
||||
In image processing, since you are dealing with large number of operations per second, it is
|
||||
mandatory that your code is not only providing the correct solution, but also in the fastest manner.
|
||||
So in this chapter, you will learn
|
||||
In image processing, since you are dealing with a large number of operations per second, it is mandatory that your code is not only providing the correct solution, but that it is also providing it in the fastest manner.
|
||||
So in this chapter, you will learn:
|
||||
|
||||
- To measure the performance of your code.
|
||||
- Some tips to improve the performance of your code.
|
||||
- You will see these functions : **cv.getTickCount**, **cv.getTickFrequency** etc.
|
||||
- You will see these functions: **cv.getTickCount**, **cv.getTickFrequency**, etc.
|
||||
|
||||
Apart from OpenCV, Python also provides a module **time** which is helpful in measuring the time of
|
||||
execution. Another module **profile** helps to get detailed report on the code, like how much time
|
||||
each function in the code took, how many times the function was called etc. But, if you are using
|
||||
execution. Another module **profile** helps to get a detailed report on the code, like how much time
|
||||
each function in the code took, how many times the function was called, etc. But, if you are using
|
||||
IPython, all these features are integrated in an user-friendly manner. We will see some important
|
||||
ones, and for more details, check links in **Additional Resources** section.
|
||||
ones, and for more details, check links in the **Additional Resources** section.
|
||||
|
||||
Measuring Performance with OpenCV
|
||||
---------------------------------
|
||||
|
||||
**cv.getTickCount** function returns the number of clock-cycles after a reference event (like the
|
||||
moment machine was switched ON) to the moment this function is called. So if you call it before and
|
||||
after the function execution, you get number of clock-cycles used to execute a function.
|
||||
The **cv.getTickCount** function returns the number of clock-cycles after a reference event (like the
|
||||
moment the machine was switched ON) to the moment this function is called. So if you call it before and
|
||||
after the function execution, you get the number of clock-cycles used to execute a function.
|
||||
|
||||
**cv.getTickFrequency** function returns the frequency of clock-cycles, or the number of
|
||||
The **cv.getTickFrequency** function returns the frequency of clock-cycles, or the number of
|
||||
clock-cycles per second. So to find the time of execution in seconds, you can do following:
|
||||
@code{.py}
|
||||
e1 = cv.getTickCount()
|
||||
@@ -33,8 +32,8 @@ e1 = cv.getTickCount()
|
||||
e2 = cv.getTickCount()
|
||||
time = (e2 - e1)/ cv.getTickFrequency()
|
||||
@endcode
|
||||
We will demonstrate with following example. Following example apply median filtering with a kernel
|
||||
of odd size ranging from 5 to 49. (Don't worry about what will the result look like, that is not our
|
||||
We will demonstrate with following example. The following example applies median filtering with kernels
|
||||
of odd sizes ranging from 5 to 49. (Don't worry about what the result will look like - that is not our
|
||||
goal):
|
||||
@code{.py}
|
||||
img1 = cv.imread('messi5.jpg')
|
||||
@@ -48,16 +47,16 @@ print( t )
|
||||
|
||||
# Result I got is 0.521107655 seconds
|
||||
@endcode
|
||||
@note You can do the same with time module. Instead of cv.getTickCount, use time.time() function.
|
||||
Then take the difference of two times.
|
||||
@note You can do the same thing with the time module. Instead of cv.getTickCount, use the time.time() function.
|
||||
Then take the difference of the two times.
|
||||
|
||||
Default Optimization in OpenCV
|
||||
------------------------------
|
||||
|
||||
Many of the OpenCV functions are optimized using SSE2, AVX etc. It contains unoptimized code also.
|
||||
Many of the OpenCV functions are optimized using SSE2, AVX, etc. It contains the unoptimized code also.
|
||||
So if our system support these features, we should exploit them (almost all modern day processors
|
||||
support them). It is enabled by default while compiling. So OpenCV runs the optimized code if it is
|
||||
enabled, else it runs the unoptimized code. You can use **cv.useOptimized()** to check if it is
|
||||
enabled, otherwise it runs the unoptimized code. You can use **cv.useOptimized()** to check if it is
|
||||
enabled/disabled and **cv.setUseOptimized()** to enable/disable it. Let's see a simple example.
|
||||
@code{.py}
|
||||
# check if optimization is enabled
|
||||
@@ -76,8 +75,8 @@ Out[8]: False
|
||||
In [9]: %timeit res = cv.medianBlur(img,49)
|
||||
10 loops, best of 3: 64.1 ms per loop
|
||||
@endcode
|
||||
See, optimized median filtering is \~2x faster than unoptimized version. If you check its source,
|
||||
you can see median filtering is SIMD optimized. So you can use this to enable optimization at the
|
||||
As you can see, optimized median filtering is \~2x faster than the unoptimized version. If you check its source,
|
||||
you can see that median filtering is SIMD optimized. So you can use this to enable optimization at the
|
||||
top of your code (remember it is enabled by default).
|
||||
|
||||
Measuring Performance in IPython
|
||||
@@ -85,10 +84,10 @@ Measuring Performance in IPython
|
||||
|
||||
Sometimes you may need to compare the performance of two similar operations. IPython gives you a
|
||||
magic command %timeit to perform this. It runs the code several times to get more accurate results.
|
||||
Once again, they are suitable to measure single line codes.
|
||||
Once again, it is suitable to measuring single lines of code.
|
||||
|
||||
For example, do you know which of the following addition operation is better, x = 5; y = x\*\*2,
|
||||
x = 5; y = x\*x, x = np.uint8([5]); y = x\*x or y = np.square(x) ? We will find it with %timeit in
|
||||
For example, do you know which of the following addition operations is better, x = 5; y = x\*\*2,
|
||||
x = 5; y = x\*x, x = np.uint8([5]); y = x\*x, or y = np.square(x)? We will find out with %timeit in the
|
||||
IPython shell.
|
||||
@code{.py}
|
||||
In [10]: x = 5
|
||||
@@ -108,15 +107,15 @@ In [19]: %timeit y=np.square(z)
|
||||
1000000 loops, best of 3: 1.16 us per loop
|
||||
@endcode
|
||||
You can see that, x = 5 ; y = x\*x is fastest and it is around 20x faster compared to Numpy. If you
|
||||
consider the array creation also, it may reach upto 100x faster. Cool, right? *(Numpy devs are
|
||||
consider the array creation also, it may reach up to 100x faster. Cool, right? *(Numpy devs are
|
||||
working on this issue)*
|
||||
|
||||
@note Python scalar operations are faster than Numpy scalar operations. So for operations including
|
||||
one or two elements, Python scalar is better than Numpy arrays. Numpy takes advantage when size of
|
||||
array is a little bit bigger.
|
||||
one or two elements, Python scalar is better than Numpy arrays. Numpy has the advantage when the size of
|
||||
the array is a little bit bigger.
|
||||
|
||||
We will try one more example. This time, we will compare the performance of **cv.countNonZero()**
|
||||
and **np.count_nonzero()** for same image.
|
||||
and **np.count_nonzero()** for the same image.
|
||||
|
||||
@code{.py}
|
||||
In [35]: %timeit z = cv.countNonZero(img)
|
||||
@@ -125,7 +124,7 @@ In [35]: %timeit z = cv.countNonZero(img)
|
||||
In [36]: %timeit z = np.count_nonzero(img)
|
||||
1000 loops, best of 3: 370 us per loop
|
||||
@endcode
|
||||
See, OpenCV function is nearly 25x faster than Numpy function.
|
||||
See, the OpenCV function is nearly 25x faster than the Numpy function.
|
||||
|
||||
@note Normally, OpenCV functions are faster than Numpy functions. So for same operation, OpenCV
|
||||
functions are preferred. But, there can be exceptions, especially when Numpy works with views
|
||||
@@ -134,8 +133,8 @@ instead of copies.
|
||||
More IPython magic commands
|
||||
---------------------------
|
||||
|
||||
There are several other magic commands to measure the performance, profiling, line profiling, memory
|
||||
measurement etc. They all are well documented. So only links to those docs are provided here.
|
||||
There are several other magic commands to measure performance, profiling, line profiling, memory
|
||||
measurement, and etc. They all are well documented. So only links to those docs are provided here.
|
||||
Interested readers are recommended to try them out.
|
||||
|
||||
Performance Optimization Techniques
|
||||
@@ -143,19 +142,18 @@ Performance Optimization Techniques
|
||||
|
||||
There are several techniques and coding methods to exploit maximum performance of Python and Numpy.
|
||||
Only relevant ones are noted here and links are given to important sources. The main thing to be
|
||||
noted here is that, first try to implement the algorithm in a simple manner. Once it is working,
|
||||
profile it, find the bottlenecks and optimize them.
|
||||
noted here is, first try to implement the algorithm in a simple manner. Once it is working,
|
||||
profile it, find the bottlenecks, and optimize them.
|
||||
|
||||
-# Avoid using loops in Python as far as possible, especially double/triple loops etc. They are
|
||||
-# Avoid using loops in Python as much as possible, especially double/triple loops etc. They are
|
||||
inherently slow.
|
||||
2. Vectorize the algorithm/code to the maximum possible extent because Numpy and OpenCV are
|
||||
2. Vectorize the algorithm/code to the maximum extent possible, because Numpy and OpenCV are
|
||||
optimized for vector operations.
|
||||
3. Exploit the cache coherence.
|
||||
4. Never make copies of array unless it is needed. Try to use views instead. Array copying is a
|
||||
4. Never make copies of an array unless it is necessary. Try to use views instead. Array copying is a
|
||||
costly operation.
|
||||
|
||||
Even after doing all these operations, if your code is still slow, or use of large loops are
|
||||
inevitable, use additional libraries like Cython to make it faster.
|
||||
If your code is still slow after doing all of these operations, or if the use of large loops is inevitable, use additional libraries like Cython to make it faster.
|
||||
|
||||
Additional Resources
|
||||
--------------------
|
||||
|
||||
@@ -43,11 +43,19 @@ points than for SURF points.
|
||||
In short, BRIEF is a faster method feature descriptor calculation and matching. It also provides
|
||||
high recognition rate unless there is large in-plane rotation.
|
||||
|
||||
STAR(CenSurE) in OpenCV
|
||||
------
|
||||
STAR is a feature detector derived from CenSurE.
|
||||
Unlike CenSurE however, which uses polygons like squares, hexagons and octagons to approach a circle,
|
||||
Star emulates a circle with 2 overlapping squares: 1 upright and 1 45-degree rotated. These polygons are bi-level.
|
||||
They can be seen as polygons with thick borders. The borders and the enclosed area have weights of opposing signs.
|
||||
This has better computational characteristics than other scale-space detectors and it is capable of real-time implementation.
|
||||
In contrast to SIFT and SURF, which find extrema at sub-sampled pixels that compromises accuracy at larger scales,
|
||||
CenSurE creates a feature vector using full spatial resolution at all scales in the pyramid.
|
||||
BRIEF in OpenCV
|
||||
---------------
|
||||
|
||||
Below code shows the computation of BRIEF descriptors with the help of CenSurE detector. (CenSurE
|
||||
detector is called STAR detector in OpenCV)
|
||||
Below code shows the computation of BRIEF descriptors with the help of CenSurE detector.
|
||||
|
||||
note, that you need [opencv contrib](https://github.com/opencv/opencv_contrib)) to use this.
|
||||
@code{.py}
|
||||
|
||||
@@ -4,21 +4,21 @@ Gui Features in OpenCV {#tutorial_py_table_of_contents_gui}
|
||||
- @subpage tutorial_py_image_display
|
||||
|
||||
Learn to load an
|
||||
image, display it and save it back
|
||||
image, display it, and save it back
|
||||
|
||||
- @subpage tutorial_py_video_display
|
||||
|
||||
Learn to play videos,
|
||||
capture videos from Camera and write it as a video
|
||||
capture videos from a camera, and write videos
|
||||
|
||||
- @subpage tutorial_py_drawing_functions
|
||||
|
||||
Learn to draw lines,
|
||||
rectangles, ellipses, circles etc with OpenCV
|
||||
rectangles, ellipses, circles, etc with OpenCV
|
||||
|
||||
- @subpage tutorial_py_mouse_handling
|
||||
|
||||
Draw stuffs with your
|
||||
Draw stuff with your
|
||||
mouse
|
||||
|
||||
- @subpage tutorial_py_trackbar
|
||||
|
||||
@@ -14,9 +14,9 @@ Here we will create a simple application which shows the color you specify. You
|
||||
shows the color and three trackbars to specify each of B,G,R colors. You slide the trackbar and
|
||||
correspondingly window color changes. By default, initial color will be set to Black.
|
||||
|
||||
For cv.getTrackbarPos() function, first argument is the trackbar name, second one is the window
|
||||
For cv.createTrackbar() function, first argument is the trackbar name, second one is the window
|
||||
name to which it is attached, third argument is the default value, fourth one is the maximum value
|
||||
and fifth one is the callback function which is executed everytime trackbar value changes. The
|
||||
and fifth one is the callback function which is executed every time trackbar value changes. The
|
||||
callback function always has a default argument which is the trackbar position. In our case,
|
||||
function does nothing, so we simply pass.
|
||||
|
||||
|
||||
@@ -4,19 +4,19 @@ Getting Started with Videos {#tutorial_py_video_display}
|
||||
Goal
|
||||
----
|
||||
|
||||
- Learn to read video, display video and save video.
|
||||
- Learn to capture from Camera and display it.
|
||||
- Learn to read video, display video, and save video.
|
||||
- Learn to capture video from a camera and display it.
|
||||
- You will learn these functions : **cv.VideoCapture()**, **cv.VideoWriter()**
|
||||
|
||||
Capture Video from Camera
|
||||
-------------------------
|
||||
|
||||
Often, we have to capture live stream with camera. OpenCV provides a very simple interface to this.
|
||||
Let's capture a video from the camera (I am using the in-built webcam of my laptop), convert it into
|
||||
Often, we have to capture live stream with a camera. OpenCV provides a very simple interface to do this.
|
||||
Let's capture a video from the camera (I am using the built-in webcam on my laptop), convert it into
|
||||
grayscale video and display it. Just a simple task to get started.
|
||||
|
||||
To capture a video, you need to create a **VideoCapture** object. Its argument can be either the
|
||||
device index or the name of a video file. Device index is just the number to specify which camera.
|
||||
device index or the name of a video file. A device index is just the number to specify which camera.
|
||||
Normally one camera will be connected (as in my case). So I simply pass 0 (or -1). You can select
|
||||
the second camera by passing 1 and so on. After that, you can capture frame-by-frame. But at the
|
||||
end, don't forget to release the capture.
|
||||
@@ -46,16 +46,16 @@ while True:
|
||||
# When everything done, release the capture
|
||||
cap.release()
|
||||
cv.destroyAllWindows()@endcode
|
||||
`cap.read()` returns a bool (`True`/`False`). If frame is read correctly, it will be `True`. So you can
|
||||
check end of the video by checking this return value.
|
||||
`cap.read()` returns a bool (`True`/`False`). If the frame is read correctly, it will be `True`. So you can
|
||||
check for the end of the video by checking this returned value.
|
||||
|
||||
Sometimes, cap may not have initialized the capture. In that case, this code shows error. You can
|
||||
Sometimes, cap may not have initialized the capture. In that case, this code shows an error. You can
|
||||
check whether it is initialized or not by the method **cap.isOpened()**. If it is `True`, OK.
|
||||
Otherwise open it using **cap.open()**.
|
||||
|
||||
You can also access some of the features of this video using **cap.get(propId)** method where propId
|
||||
is a number from 0 to 18. Each number denotes a property of the video (if it is applicable to that
|
||||
video) and full details can be seen here: cv::VideoCapture::get().
|
||||
video). Full details can be seen here: cv::VideoCapture::get().
|
||||
Some of these values can be modified using **cap.set(propId, value)**. Value is the new value you
|
||||
want.
|
||||
|
||||
@@ -63,13 +63,13 @@ For example, I can check the frame width and height by `cap.get(cv.CAP_PROP_FRAM
|
||||
640x480 by default. But I want to modify it to 320x240. Just use `ret = cap.set(cv.CAP_PROP_FRAME_WIDTH,320)` and
|
||||
`ret = cap.set(cv.CAP_PROP_FRAME_HEIGHT,240)`.
|
||||
|
||||
@note If you are getting error, make sure camera is working fine using any other camera application
|
||||
@note If you are getting an error, make sure your camera is working fine using any other camera application
|
||||
(like Cheese in Linux).
|
||||
|
||||
Playing Video from file
|
||||
-----------------------
|
||||
|
||||
It is same as capturing from Camera, just change camera index with video file name. Also while
|
||||
Playing video from file is the same as capturing it from camera, just change the camera index to a video file name. Also while
|
||||
displaying the frame, use appropriate time for `cv.waitKey()`. If it is too less, video will be very
|
||||
fast and if it is too high, video will be slow (Well, that is how you can display videos in slow
|
||||
motion). 25 milliseconds will be OK in normal cases.
|
||||
@@ -96,23 +96,23 @@ cap.release()
|
||||
cv.destroyAllWindows()
|
||||
@endcode
|
||||
|
||||
@note Make sure proper versions of ffmpeg or gstreamer is installed. Sometimes, it is a headache to
|
||||
work with Video Capture mostly due to wrong installation of ffmpeg/gstreamer.
|
||||
@note Make sure a proper version of ffmpeg or gstreamer is installed. Sometimes it is a headache to
|
||||
work with video capture, mostly due to wrong installation of ffmpeg/gstreamer.
|
||||
|
||||
Saving a Video
|
||||
--------------
|
||||
|
||||
So we capture a video, process it frame-by-frame and we want to save that video. For images, it is
|
||||
very simple, just use `cv.imwrite()`. Here a little more work is required.
|
||||
So we capture a video and process it frame-by-frame, and we want to save that video. For images, it is
|
||||
very simple: just use `cv.imwrite()`. Here, a little more work is required.
|
||||
|
||||
This time we create a **VideoWriter** object. We should specify the output file name (eg:
|
||||
output.avi). Then we should specify the **FourCC** code (details in next paragraph). Then number of
|
||||
frames per second (fps) and frame size should be passed. And last one is **isColor** flag. If it is
|
||||
`True`, encoder expect color frame, otherwise it works with grayscale frame.
|
||||
frames per second (fps) and frame size should be passed. And the last one is the **isColor** flag. If it is
|
||||
`True`, the encoder expect color frame, otherwise it works with grayscale frame.
|
||||
|
||||
[FourCC](http://en.wikipedia.org/wiki/FourCC) is a 4-byte code used to specify the video codec. The
|
||||
list of available codes can be found in [fourcc.org](http://www.fourcc.org/codecs.php). It is
|
||||
platform dependent. Following codecs works fine for me.
|
||||
platform dependent. The following codecs work fine for me.
|
||||
|
||||
- In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID is more preferable. MJPG results in high
|
||||
size video. X264 gives very small size video)
|
||||
@@ -122,7 +122,7 @@ platform dependent. Following codecs works fine for me.
|
||||
FourCC code is passed as `cv.VideoWriter_fourcc('M','J','P','G')` or
|
||||
`cv.VideoWriter_fourcc(*'MJPG')` for MJPG.
|
||||
|
||||
Below code capture from a Camera, flip every frame in vertical direction and saves it.
|
||||
The below code captures from a camera, flips every frame in the vertical direction, and saves the video.
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
@@ -5,44 +5,44 @@ Goal
|
||||
----
|
||||
|
||||
- In this tutorial, you will learn how to convert images from one color-space to another, like
|
||||
BGR \f$\leftrightarrow\f$ Gray, BGR \f$\leftrightarrow\f$ HSV etc.
|
||||
- In addition to that, we will create an application which extracts a colored object in a video
|
||||
- You will learn following functions : **cv.cvtColor()**, **cv.inRange()** etc.
|
||||
BGR \f$\leftrightarrow\f$ Gray, BGR \f$\leftrightarrow\f$ HSV, etc.
|
||||
- In addition to that, we will create an application to extract a colored object in a video
|
||||
- You will learn the following functions: **cv.cvtColor()**, **cv.inRange()**, etc.
|
||||
|
||||
Changing Color-space
|
||||
--------------------
|
||||
|
||||
There are more than 150 color-space conversion methods available in OpenCV. But we will look into
|
||||
only two which are most widely used ones, BGR \f$\leftrightarrow\f$ Gray and BGR \f$\leftrightarrow\f$ HSV.
|
||||
only two, which are most widely used ones: BGR \f$\leftrightarrow\f$ Gray and BGR \f$\leftrightarrow\f$ HSV.
|
||||
|
||||
For color conversion, we use the function cv.cvtColor(input_image, flag) where flag determines the
|
||||
type of conversion.
|
||||
|
||||
For BGR \f$\rightarrow\f$ Gray conversion we use the flags cv.COLOR_BGR2GRAY. Similarly for BGR
|
||||
For BGR \f$\rightarrow\f$ Gray conversion, we use the flag cv.COLOR_BGR2GRAY. Similarly for BGR
|
||||
\f$\rightarrow\f$ HSV, we use the flag cv.COLOR_BGR2HSV. To get other flags, just run following
|
||||
commands in your Python terminal :
|
||||
commands in your Python terminal:
|
||||
@code{.py}
|
||||
>>> import cv2 as cv
|
||||
>>> flags = [i for i in dir(cv) if i.startswith('COLOR_')]
|
||||
>>> print( flags )
|
||||
@endcode
|
||||
@note For HSV, Hue range is [0,179], Saturation range is [0,255] and Value range is [0,255].
|
||||
@note For HSV, hue range is [0,179], saturation range is [0,255], and value range is [0,255].
|
||||
Different software use different scales. So if you are comparing OpenCV values with them, you need
|
||||
to normalize these ranges.
|
||||
|
||||
Object Tracking
|
||||
---------------
|
||||
|
||||
Now we know how to convert BGR image to HSV, we can use this to extract a colored object. In HSV, it
|
||||
is more easier to represent a color than in BGR color-space. In our application, we will try to extract
|
||||
Now that we know how to convert a BGR image to HSV, we can use this to extract a colored object. In HSV, it
|
||||
is easier to represent a color than in BGR color-space. In our application, we will try to extract
|
||||
a blue colored object. So here is the method:
|
||||
|
||||
- Take each frame of the video
|
||||
- Convert from BGR to HSV color-space
|
||||
- We threshold the HSV image for a range of blue color
|
||||
- Now extract the blue object alone, we can do whatever on that image we want.
|
||||
- Now extract the blue object alone, we can do whatever we want on that image.
|
||||
|
||||
Below is the code which are commented in detail :
|
||||
Below is the code which is commented in detail:
|
||||
@code{.py}
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
@@ -80,18 +80,18 @@ Below image shows tracking of the blue object:
|
||||
|
||||

|
||||
|
||||
@note There are some noises in the image. We will see how to remove them in later chapters.
|
||||
@note There is some noise in the image. We will see how to remove it in later chapters.
|
||||
|
||||
@note This is the simplest method in object tracking. Once you learn functions of contours, you can
|
||||
do plenty of things like find centroid of this object and use it to track the object, draw diagrams
|
||||
just by moving your hand in front of camera and many other funny stuffs.
|
||||
do plenty of things like find the centroid of an object and use it to track the object, draw diagrams
|
||||
just by moving your hand in front of a camera, and other fun stuff.
|
||||
|
||||
How to find HSV values to track?
|
||||
--------------------------------
|
||||
|
||||
This is a common question found in [stackoverflow.com](http://www.stackoverflow.com). It is very simple and
|
||||
you can use the same function, cv.cvtColor(). Instead of passing an image, you just pass the BGR
|
||||
values you want. For example, to find the HSV value of Green, try following commands in Python
|
||||
values you want. For example, to find the HSV value of Green, try the following commands in a Python
|
||||
terminal:
|
||||
@code{.py}
|
||||
>>> green = np.uint8([[[0,255,0 ]]])
|
||||
@@ -99,7 +99,7 @@ terminal:
|
||||
>>> print( hsv_green )
|
||||
[[[ 60 255 255]]]
|
||||
@endcode
|
||||
Now you take [H-10, 100,100] and [H+10, 255, 255] as lower bound and upper bound respectively. Apart
|
||||
Now you take [H-10, 100,100] and [H+10, 255, 255] as the lower bound and upper bound respectively. Apart
|
||||
from this method, you can use any image editing tools like GIMP or any online converters to find
|
||||
these values, but don't forget to adjust the HSV ranges.
|
||||
|
||||
@@ -109,5 +109,5 @@ Additional Resources
|
||||
Exercises
|
||||
---------
|
||||
|
||||
-# Try to find a way to extract more than one colored objects, for eg, extract red, blue, green
|
||||
objects simultaneously.
|
||||
-# Try to find a way to extract more than one colored object, for example, extract red, blue, and green
|
||||
objects simultaneously.
|
||||
|
||||
@@ -5,24 +5,24 @@ Goals
|
||||
-----
|
||||
|
||||
Learn to:
|
||||
- Blur the images with various low pass filters
|
||||
- Blur images with various low pass filters
|
||||
- Apply custom-made filters to images (2D convolution)
|
||||
|
||||
2D Convolution ( Image Filtering )
|
||||
----------------------------------
|
||||
|
||||
As in one-dimensional signals, images also can be filtered with various low-pass filters(LPF),
|
||||
high-pass filters(HPF) etc. LPF helps in removing noises, blurring the images etc. HPF filters helps
|
||||
in finding edges in the images.
|
||||
As in one-dimensional signals, images also can be filtered with various low-pass filters (LPF),
|
||||
high-pass filters (HPF), etc. LPF helps in removing noise, blurring images, etc. HPF filters help
|
||||
in finding edges in images.
|
||||
|
||||
OpenCV provides a function **cv.filter2D()** to convolve a kernel with an image. As an example, we
|
||||
will try an averaging filter on an image. A 5x5 averaging filter kernel will look like below:
|
||||
will try an averaging filter on an image. A 5x5 averaging filter kernel will look like the below:
|
||||
|
||||
\f[K = \frac{1}{25} \begin{bmatrix} 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \end{bmatrix}\f]
|
||||
|
||||
Operation is like this: keep this kernel above a pixel, add all the 25 pixels below this kernel,
|
||||
take its average and replace the central pixel with the new average value. It continues this
|
||||
operation for all the pixels in the image. Try this code and check the result:
|
||||
The operation works like this: keep this kernel above a pixel, add all the 25 pixels below this kernel,
|
||||
take the average, and replace the central pixel with the new average value. This operation is continued
|
||||
for all the pixels in the image. Try this code and check the result:
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
@@ -47,20 +47,20 @@ Image Blurring (Image Smoothing)
|
||||
--------------------------------
|
||||
|
||||
Image blurring is achieved by convolving the image with a low-pass filter kernel. It is useful for
|
||||
removing noises. It actually removes high frequency content (eg: noise, edges) from the image. So
|
||||
edges are blurred a little bit in this operation. (Well, there are blurring techniques which doesn't
|
||||
blur the edges too). OpenCV provides mainly four types of blurring techniques.
|
||||
removing noise. It actually removes high frequency content (eg: noise, edges) from the image. So
|
||||
edges are blurred a little bit in this operation (there are also blurring techniques which don't
|
||||
blur the edges). OpenCV provides four main types of blurring techniques.
|
||||
|
||||
### 1. Averaging
|
||||
|
||||
This is done by convolving image with a normalized box filter. It simply takes the average of all
|
||||
the pixels under kernel area and replace the central element. This is done by the function
|
||||
This is done by convolving an image with a normalized box filter. It simply takes the average of all
|
||||
the pixels under the kernel area and replaces the central element. This is done by the function
|
||||
**cv.blur()** or **cv.boxFilter()**. Check the docs for more details about the kernel. We should
|
||||
specify the width and height of kernel. A 3x3 normalized box filter would look like below:
|
||||
specify the width and height of the kernel. A 3x3 normalized box filter would look like the below:
|
||||
|
||||
\f[K = \frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix}\f]
|
||||
|
||||
@note If you don't want to use normalized box filter, use **cv.boxFilter()**. Pass an argument
|
||||
@note If you don't want to use a normalized box filter, use **cv.boxFilter()**. Pass an argument
|
||||
normalize=False to the function.
|
||||
|
||||
Check a sample demo below with a kernel of 5x5 size:
|
||||
@@ -85,12 +85,12 @@ Result:
|
||||
|
||||
### 2. Gaussian Blurring
|
||||
|
||||
In this, instead of box filter, gaussian kernel is used. It is done with the function,
|
||||
**cv.GaussianBlur()**. We should specify the width and height of kernel which should be positive
|
||||
and odd. We also should specify the standard deviation in X and Y direction, sigmaX and sigmaY
|
||||
respectively. If only sigmaX is specified, sigmaY is taken as same as sigmaX. If both are given as
|
||||
zeros, they are calculated from kernel size. Gaussian blurring is highly effective in removing
|
||||
gaussian noise from the image.
|
||||
In this method, instead of a box filter, a Gaussian kernel is used. It is done with the function,
|
||||
**cv.GaussianBlur()**. We should specify the width and height of the kernel which should be positive
|
||||
and odd. We also should specify the standard deviation in the X and Y directions, sigmaX and sigmaY
|
||||
respectively. If only sigmaX is specified, sigmaY is taken as the same as sigmaX. If both are given as
|
||||
zeros, they are calculated from the kernel size. Gaussian blurring is highly effective in removing
|
||||
Gaussian noise from an image.
|
||||
|
||||
If you want, you can create a Gaussian kernel with the function, **cv.getGaussianKernel()**.
|
||||
|
||||
@@ -104,14 +104,14 @@ Result:
|
||||
|
||||
### 3. Median Blurring
|
||||
|
||||
Here, the function **cv.medianBlur()** takes median of all the pixels under kernel area and central
|
||||
Here, the function **cv.medianBlur()** takes the median of all the pixels under the kernel area and the central
|
||||
element is replaced with this median value. This is highly effective against salt-and-pepper noise
|
||||
in the images. Interesting thing is that, in the above filters, central element is a newly
|
||||
in an image. Interestingly, in the above filters, the central element is a newly
|
||||
calculated value which may be a pixel value in the image or a new value. But in median blurring,
|
||||
central element is always replaced by some pixel value in the image. It reduces the noise
|
||||
the central element is always replaced by some pixel value in the image. It reduces the noise
|
||||
effectively. Its kernel size should be a positive odd integer.
|
||||
|
||||
In this demo, I added a 50% noise to our original image and applied median blur. Check the result:
|
||||
In this demo, I added a 50% noise to our original image and applied median blurring. Check the result:
|
||||
@code{.py}
|
||||
median = cv.medianBlur(img,5)
|
||||
@endcode
|
||||
@@ -122,19 +122,19 @@ Result:
|
||||
### 4. Bilateral Filtering
|
||||
|
||||
**cv.bilateralFilter()** is highly effective in noise removal while keeping edges sharp. But the
|
||||
operation is slower compared to other filters. We already saw that gaussian filter takes the a
|
||||
neighbourhood around the pixel and find its gaussian weighted average. This gaussian filter is a
|
||||
operation is slower compared to other filters. We already saw that a Gaussian filter takes the
|
||||
neighbourhood around the pixel and finds its Gaussian weighted average. This Gaussian filter is a
|
||||
function of space alone, that is, nearby pixels are considered while filtering. It doesn't consider
|
||||
whether pixels have almost same intensity. It doesn't consider whether pixel is an edge pixel or
|
||||
whether pixels have almost the same intensity. It doesn't consider whether a pixel is an edge pixel or
|
||||
not. So it blurs the edges also, which we don't want to do.
|
||||
|
||||
Bilateral filter also takes a gaussian filter in space, but one more gaussian filter which is a
|
||||
function of pixel difference. Gaussian function of space make sure only nearby pixels are considered
|
||||
for blurring while gaussian function of intensity difference make sure only those pixels with
|
||||
similar intensity to central pixel is considered for blurring. So it preserves the edges since
|
||||
Bilateral filtering also takes a Gaussian filter in space, but one more Gaussian filter which is a
|
||||
function of pixel difference. The Gaussian function of space makes sure that only nearby pixels are considered
|
||||
for blurring, while the Gaussian function of intensity difference makes sure that only those pixels with
|
||||
similar intensities to the central pixel are considered for blurring. So it preserves the edges since
|
||||
pixels at edges will have large intensity variation.
|
||||
|
||||
Below samples shows use bilateral filter (For details on arguments, visit docs).
|
||||
The below sample shows use of a bilateral filter (For details on arguments, visit docs).
|
||||
@code{.py}
|
||||
blur = cv.bilateralFilter(img,9,75,75)
|
||||
@endcode
|
||||
@@ -142,7 +142,7 @@ Result:
|
||||
|
||||

|
||||
|
||||
See, the texture on the surface is gone, but edges are still preserved.
|
||||
See, the texture on the surface is gone, but the edges are still preserved.
|
||||
|
||||
Additional Resources
|
||||
--------------------
|
||||
|
||||
+14
-14
@@ -4,7 +4,7 @@ Geometric Transformations of Images {#tutorial_py_geometric_transformations}
|
||||
Goals
|
||||
-----
|
||||
|
||||
- Learn to apply different geometric transformation to images like translation, rotation, affine
|
||||
- Learn to apply different geometric transformations to images, like translation, rotation, affine
|
||||
transformation etc.
|
||||
- You will see these functions: **cv.getPerspectiveTransform**
|
||||
|
||||
@@ -12,7 +12,7 @@ Transformations
|
||||
---------------
|
||||
|
||||
OpenCV provides two transformation functions, **cv.warpAffine** and **cv.warpPerspective**, with
|
||||
which you can have all kinds of transformations. **cv.warpAffine** takes a 2x3 transformation
|
||||
which you can perform all kinds of transformations. **cv.warpAffine** takes a 2x3 transformation
|
||||
matrix while **cv.warpPerspective** takes a 3x3 transformation matrix as input.
|
||||
|
||||
### Scaling
|
||||
@@ -21,8 +21,8 @@ Scaling is just resizing of the image. OpenCV comes with a function **cv.resize(
|
||||
purpose. The size of the image can be specified manually, or you can specify the scaling factor.
|
||||
Different interpolation methods are used. Preferable interpolation methods are **cv.INTER_AREA**
|
||||
for shrinking and **cv.INTER_CUBIC** (slow) & **cv.INTER_LINEAR** for zooming. By default,
|
||||
interpolation method used is **cv.INTER_LINEAR** for all resizing purposes. You can resize an
|
||||
input image either of following methods:
|
||||
the interpolation method **cv.INTER_LINEAR** is used for all resizing purposes. You can resize an
|
||||
input image with either of following methods:
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
@@ -38,13 +38,13 @@ res = cv.resize(img,(2*width, 2*height), interpolation = cv.INTER_CUBIC)
|
||||
@endcode
|
||||
### Translation
|
||||
|
||||
Translation is the shifting of object's location. If you know the shift in (x,y) direction, let it
|
||||
Translation is the shifting of an object's location. If you know the shift in the (x,y) direction and let it
|
||||
be \f$(t_x,t_y)\f$, you can create the transformation matrix \f$\textbf{M}\f$ as follows:
|
||||
|
||||
\f[M = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \end{bmatrix}\f]
|
||||
|
||||
You can take make it into a Numpy array of type np.float32 and pass it into **cv.warpAffine()**
|
||||
function. See below example for a shift of (100,50):
|
||||
You can take make it into a Numpy array of type np.float32 and pass it into the **cv.warpAffine()**
|
||||
function. See the below example for a shift of (100,50):
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
@@ -61,7 +61,7 @@ cv.destroyAllWindows()
|
||||
@endcode
|
||||
**warning**
|
||||
|
||||
Third argument of the **cv.warpAffine()** function is the size of the output image, which should
|
||||
The third argument of the **cv.warpAffine()** function is the size of the output image, which should
|
||||
be in the form of **(width, height)**. Remember width = number of columns, and height = number of
|
||||
rows.
|
||||
|
||||
@@ -76,7 +76,7 @@ Rotation of an image for an angle \f$\theta\f$ is achieved by the transformation
|
||||
\f[M = \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix}\f]
|
||||
|
||||
But OpenCV provides scaled rotation with adjustable center of rotation so that you can rotate at any
|
||||
location you prefer. Modified transformation matrix is given by
|
||||
location you prefer. The modified transformation matrix is given by
|
||||
|
||||
\f[\begin{bmatrix} \alpha & \beta & (1- \alpha ) \cdot center.x - \beta \cdot center.y \\ - \beta & \alpha & \beta \cdot center.x + (1- \alpha ) \cdot center.y \end{bmatrix}\f]
|
||||
|
||||
@@ -84,7 +84,7 @@ where:
|
||||
|
||||
\f[\begin{array}{l} \alpha = scale \cdot \cos \theta , \\ \beta = scale \cdot \sin \theta \end{array}\f]
|
||||
|
||||
To find this transformation matrix, OpenCV provides a function, **cv.getRotationMatrix2D**. Check
|
||||
To find this transformation matrix, OpenCV provides a function, **cv.getRotationMatrix2D**. Check out the
|
||||
below example which rotates the image by 90 degree with respect to center without any scaling.
|
||||
@code{.py}
|
||||
img = cv.imread('messi5.jpg',0)
|
||||
@@ -101,11 +101,11 @@ See the result:
|
||||
### Affine Transformation
|
||||
|
||||
In affine transformation, all parallel lines in the original image will still be parallel in the
|
||||
output image. To find the transformation matrix, we need three points from input image and their
|
||||
corresponding locations in output image. Then **cv.getAffineTransform** will create a 2x3 matrix
|
||||
output image. To find the transformation matrix, we need three points from the input image and their
|
||||
corresponding locations in the output image. Then **cv.getAffineTransform** will create a 2x3 matrix
|
||||
which is to be passed to **cv.warpAffine**.
|
||||
|
||||
Check below example, and also look at the points I selected (which are marked in Green color):
|
||||
Check the below example, and also look at the points I selected (which are marked in green color):
|
||||
@code{.py}
|
||||
img = cv.imread('drawing.png')
|
||||
rows,cols,ch = img.shape
|
||||
@@ -130,7 +130,7 @@ See the result:
|
||||
For perspective transformation, you need a 3x3 transformation matrix. Straight lines will remain
|
||||
straight even after the transformation. To find this transformation matrix, you need 4 points on the
|
||||
input image and corresponding points on the output image. Among these 4 points, 3 of them should not
|
||||
be collinear. Then transformation matrix can be found by the function
|
||||
be collinear. Then the transformation matrix can be found by the function
|
||||
**cv.getPerspectiveTransform**. Then apply **cv.warpPerspective** with this 3x3 transformation
|
||||
matrix.
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ Image Thresholding {#tutorial_py_thresholding}
|
||||
Goal
|
||||
----
|
||||
|
||||
- In this tutorial, you will learn Simple thresholding, Adaptive thresholding and Otsu's thresholding.
|
||||
- In this tutorial, you will learn simple thresholding, adaptive thresholding and Otsu's thresholding.
|
||||
- You will learn the functions **cv.threshold** and **cv.adaptiveThreshold**.
|
||||
|
||||
Simple Thresholding
|
||||
-------------------
|
||||
|
||||
Here, the matter is straight forward. For every pixel, the same threshold value is applied.
|
||||
Here, the matter is straight-forward. For every pixel, the same threshold value is applied.
|
||||
If the pixel value is smaller than the threshold, it is set to 0, otherwise it is set to a maximum value.
|
||||
The function **cv.threshold** is used to apply the thresholding.
|
||||
The first argument is the source image, which **should be a grayscale image**.
|
||||
@@ -65,11 +65,11 @@ Adaptive Thresholding
|
||||
|
||||
In the previous section, we used one global value as a threshold.
|
||||
But this might not be good in all cases, e.g. if an image has different lighting conditions in different areas.
|
||||
In that case, adaptive thresholding thresholding can help.
|
||||
In that case, adaptive thresholding can help.
|
||||
Here, the algorithm determines the threshold for a pixel based on a small region around it.
|
||||
So we get different thresholds for different regions of the same image which gives better results for images with varying illumination.
|
||||
|
||||
Additionally to the parameters described above, the method cv.adaptiveThreshold three input parameters:
|
||||
In addition to the parameters described above, the method cv.adaptiveThreshold takes three input parameters:
|
||||
|
||||
The **adaptiveMethod** decides how the threshold value is calculated:
|
||||
- cv.ADAPTIVE_THRESH_MEAN_C: The threshold value is the mean of the neighbourhood area minus the constant **C**.
|
||||
@@ -168,8 +168,8 @@ Result:
|
||||
|
||||
### How does Otsu's Binarization work?
|
||||
|
||||
This section demonstrates a Python implementation of Otsu's binarization to show how it works
|
||||
actually. If you are not interested, you can skip this.
|
||||
This section demonstrates a Python implementation of Otsu's binarization to show how it actually
|
||||
works. If you are not interested, you can skip this.
|
||||
|
||||
Since we are working with bimodal images, Otsu's algorithm tries to find a threshold value (t) which
|
||||
minimizes the **weighted within-class variance** given by the relation:
|
||||
|
||||
@@ -54,7 +54,7 @@ print( accuracy )
|
||||
@endcode
|
||||
So our basic OCR app is ready. This particular example gave me an accuracy of 91%. One option
|
||||
improve accuracy is to add more data for training, especially the wrong ones. So instead of finding
|
||||
this training data everytime I start application, I better save it, so that next time, I directly
|
||||
this training data every time I start application, I better save it, so that next time, I directly
|
||||
read this data from a file and start classification. You can do it with the help of some Numpy
|
||||
functions like np.savetxt, np.savez, np.load etc. Please check their docs for more details.
|
||||
@code{.py}
|
||||
|
||||
@@ -150,7 +150,7 @@ We observe that @ref cv::Mat::zeros returns a Matlab-style zero initializer base
|
||||
|
||||
Notice the following (**C++ code only**):
|
||||
- To access each pixel in the images we are using this syntax: *image.at\<Vec3b\>(y,x)[c]*
|
||||
where *y* is the row, *x* is the column and *c* is R, G or B (0, 1 or 2).
|
||||
where *y* is the row, *x* is the column and *c* is B, G or R (0, 1 or 2).
|
||||
- Since the operation \f$\alpha \cdot p(i,j) + \beta\f$ can give values out of range or not
|
||||
integers (if \f$\alpha\f$ is float), we use cv::saturate_cast to make sure the
|
||||
values are valid.
|
||||
@@ -220,12 +220,12 @@ gamma correction.
|
||||
### Brightness and contrast adjustments
|
||||
|
||||
Increasing (/ decreasing) the \f$\beta\f$ value will add (/ subtract) a constant value to every pixel. Pixel values outside of the [0 ; 255]
|
||||
range will be saturated (i.e. a pixel value higher (/ lesser) than 255 (/ 0) will be clamp to 255 (/ 0)).
|
||||
range will be saturated (i.e. a pixel value higher (/ lesser) than 255 (/ 0) will be clamped to 255 (/ 0)).
|
||||
|
||||

|
||||
|
||||
The histogram represents for each color level the number of pixels with that color level. A dark image will have many pixels with
|
||||
low color value and thus the histogram will present a peak in his left part. When adding a constant bias, the histogram is shifted to the
|
||||
low color value and thus the histogram will present a peak in its left part. When adding a constant bias, the histogram is shifted to the
|
||||
right as we have added a constant bias to all the pixels.
|
||||
|
||||
The \f$\alpha\f$ parameter will modify how the levels spread. If \f$ \alpha < 1 \f$, the color levels will be compressed and the result
|
||||
|
||||
@@ -10,7 +10,7 @@ Goal
|
||||
We'll seek answers for the following questions:
|
||||
|
||||
- How to go through each and every pixel of an image?
|
||||
- How is OpenCV matrix values stored?
|
||||
- How are OpenCV matrix values stored?
|
||||
- How to measure the performance of our algorithm?
|
||||
- What are lookup tables and why use them?
|
||||
|
||||
@@ -45,13 +45,13 @@ operation. In case of the *uchar* system this is 256 to be exact.
|
||||
Therefore, for larger images it would be wise to calculate all possible values beforehand and during
|
||||
the assignment just make the assignment, by using a lookup table. Lookup tables are simple arrays
|
||||
(having one or more dimensions) that for a given input value variation holds the final output value.
|
||||
Its strength lies that we do not need to make the calculation, we just need to read the result.
|
||||
Its strength is that we do not need to make the calculation, we just need to read the result.
|
||||
|
||||
Our test case program (and the sample presented here) will do the following: read in a console line
|
||||
argument image (that may be either color or gray scale - console line argument too) and apply the
|
||||
reduction with the given console line argument integer value. In OpenCV, at the moment there are
|
||||
Our test case program (and the code sample below) will do the following: read in an image passed
|
||||
as a command line argument (it may be either color or grayscale) and apply the reduction
|
||||
with the given command line argument integer value. In OpenCV, at the moment there are
|
||||
three major ways of going through an image pixel by pixel. To make things a little more interesting
|
||||
will make the scanning for each image using all of these methods, and print out how long it took.
|
||||
we'll make the scanning of the image using each of these methods, and print out how long it took.
|
||||
|
||||
You can download the full source code [here
|
||||
](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp) or look it up in
|
||||
@@ -59,7 +59,7 @@ the samples directory of OpenCV at the cpp tutorial code for the core section. I
|
||||
@code{.bash}
|
||||
how_to_scan_images imageName.jpg intValueToReduce [G]
|
||||
@endcode
|
||||
The final argument is optional. If given the image will be loaded in gray scale format, otherwise
|
||||
The final argument is optional. If given the image will be loaded in grayscale format, otherwise
|
||||
the BGR color space is used. The first thing is to calculate the lookup table.
|
||||
|
||||
@snippet how_to_scan_images.cpp dividewith
|
||||
@@ -71,8 +71,8 @@ No OpenCV specific stuff here.
|
||||
Another issue is how do we measure time? Well OpenCV offers two simple functions to achieve this
|
||||
cv::getTickCount() and cv::getTickFrequency() . The first returns the number of ticks of
|
||||
your systems CPU from a certain event (like since you booted your system). The second returns how
|
||||
many times your CPU emits a tick during a second. So to measure in seconds the number of time
|
||||
elapsed between two operations is easy as:
|
||||
many times your CPU emits a tick during a second. So, measuring amount of time elapsed between
|
||||
two operations is as easy as:
|
||||
@code{.cpp}
|
||||
double t = (double)getTickCount();
|
||||
// do something ...
|
||||
@@ -85,8 +85,8 @@ How is the image matrix stored in memory?
|
||||
-----------------------------------------
|
||||
|
||||
As you could already read in my @ref tutorial_mat_the_basic_image_container tutorial the size of the matrix
|
||||
depends on the color system used. More accurately, it depends from the number of channels used. In
|
||||
case of a gray scale image we have something like:
|
||||
depends on the color system used. More accurately, it depends on the number of channels used. In
|
||||
case of a grayscale image we have something like:
|
||||
|
||||

|
||||
|
||||
@@ -117,12 +117,12 @@ three channels so we need to pass through three times more items in each row.
|
||||
There's another way of this. The *data* data member of a *Mat* object returns the pointer to the
|
||||
first row, first column. If this pointer is null you have no valid input in that object. Checking
|
||||
this is the simplest method to check if your image loading was a success. In case the storage is
|
||||
continuous we can use this to go through the whole data pointer. In case of a gray scale image this
|
||||
continuous we can use this to go through the whole data pointer. In case of a grayscale image this
|
||||
would look like:
|
||||
@code{.cpp}
|
||||
uchar* p = I.data;
|
||||
|
||||
for( unsigned int i =0; i < ncol*nrows; ++i)
|
||||
for( unsigned int i = 0; i < ncol*nrows; ++i)
|
||||
*p++ = table[*p];
|
||||
@endcode
|
||||
You would get the same result. However, this code is a lot harder to read later on. It gets even
|
||||
@@ -135,7 +135,7 @@ The iterator (safe) method
|
||||
|
||||
In case of the efficient way making sure that you pass through the right amount of *uchar* fields
|
||||
and to skip the gaps that may occur between the rows was your responsibility. The iterator method is
|
||||
considered a safer way as it takes over these tasks from the user. All you need to do is ask the
|
||||
considered a safer way as it takes over these tasks from the user. All you need to do is to ask the
|
||||
begin and the end of the image matrix and then just increase the begin iterator until you reach the
|
||||
end. To acquire the value *pointed* by the iterator use the \* operator (add it before it).
|
||||
|
||||
@@ -152,17 +152,17 @@ On-the-fly address calculation with reference returning
|
||||
|
||||
The final method isn't recommended for scanning. It was made to acquire or modify somehow random
|
||||
elements in the image. Its basic usage is to specify the row and column number of the item you want
|
||||
to access. During our earlier scanning methods you could already observe that is important through
|
||||
to access. During our earlier scanning methods you could already notice that it is important through
|
||||
what type we are looking at the image. It's no different here as you need to manually specify what
|
||||
type to use at the automatic lookup. You can observe this in case of the gray scale images for the
|
||||
type to use at the automatic lookup. You can observe this in case of the grayscale images for the
|
||||
following source code (the usage of the + cv::Mat::at() function):
|
||||
|
||||
@snippet how_to_scan_images.cpp scan-random
|
||||
|
||||
The functions takes your input type and coordinates and calculates on the fly the address of the
|
||||
The function takes your input type and coordinates and calculates the address of the
|
||||
queried item. Then returns a reference to that. This may be a constant when you *get* the value and
|
||||
non-constant when you *set* the value. As a safety step in **debug mode only**\* there is performed
|
||||
a check that your input coordinates are valid and does exist. If this isn't the case you'll get a
|
||||
non-constant when you *set* the value. As a safety step in **debug mode only**\* there is a check
|
||||
performed that your input coordinates are valid and do exist. If this isn't the case you'll get a
|
||||
nice output message of this on the standard error output stream. Compared to the efficient way in
|
||||
release mode the only difference in using this is that for every element of the image you'll get a
|
||||
new row pointer for what we use the C operator[] to acquire the column element.
|
||||
@@ -173,7 +173,7 @@ OpenCV has a cv::Mat_ data type. It's the same as Mat with the extra need that a
|
||||
you need to specify the data type through what to look at the data matrix, however in return you can
|
||||
use the operator() for fast access of items. To make things even better this is easily convertible
|
||||
from and to the usual cv::Mat data type. A sample usage of this you can see in case of the
|
||||
color images of the upper function. Nevertheless, it's important to note that the same operation
|
||||
color images of the function above. Nevertheless, it's important to note that the same operation
|
||||
(with the same runtime speed) could have been done with the cv::Mat::at function. It's just a less
|
||||
to write for the lazy programmer trick.
|
||||
|
||||
@@ -195,7 +195,7 @@ Finally call the function (I is our input image and J the output one):
|
||||
Performance Difference
|
||||
----------------------
|
||||
|
||||
For the best result compile the program and run it on your own speed. To make the differences more
|
||||
For the best result compile the program and run it yourself. To make the differences more
|
||||
clear, I've used a quite large (2560 X 1600) image. The performance presented here are for
|
||||
color images. For a more accurate value I've averaged the value I got from the call of the function
|
||||
for hundred times.
|
||||
|
||||
@@ -4,7 +4,7 @@ Mask operations on matrices {#tutorial_mat_mask_operations}
|
||||
@prev_tutorial{tutorial_how_to_scan_images}
|
||||
@next_tutorial{tutorial_mat_operations}
|
||||
|
||||
Mask operations on matrices are quite simple. The idea is that we recalculate each pixels value in
|
||||
Mask operations on matrices are quite simple. The idea is that we recalculate each pixel's value in
|
||||
an image according to a mask matrix (also known as kernel). This mask holds values that will adjust
|
||||
how much influence neighboring pixels (and the current pixel) have on the new pixel value. From a
|
||||
mathematical point of view we make a weighted average, with our specified values.
|
||||
@@ -12,7 +12,7 @@ mathematical point of view we make a weighted average, with our specified values
|
||||
Our test case
|
||||
-------------
|
||||
|
||||
Let us consider the issue of an image contrast enhancement method. Basically we want to apply for
|
||||
Let's consider the issue of an image contrast enhancement method. Basically we want to apply for
|
||||
every pixel of the image the following formula:
|
||||
|
||||
\f[I(i,j) = 5*I(i,j) - [ I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]\f]\f[\iff I(i,j)*M, \text{where }
|
||||
@@ -144,7 +144,7 @@ Then we apply the sum and put the new value in the Result matrix.
|
||||
The filter2D function
|
||||
---------------------
|
||||
|
||||
Applying such filters are so common in image processing that in OpenCV there exist a function that
|
||||
Applying such filters are so common in image processing that in OpenCV there is a function that
|
||||
will take care of applying the mask (also called a kernel in some places). For this you first need
|
||||
to define an object that holds the mask:
|
||||
|
||||
|
||||
+20
-20
@@ -61,7 +61,7 @@ The last thing we want to do is further decrease the speed of your program by ma
|
||||
copies of potentially *large* images.
|
||||
|
||||
To tackle this issue OpenCV uses a reference counting system. The idea is that each *Mat* object has
|
||||
its own header, however the matrix may be shared between two instance of them by having their matrix
|
||||
its own header, however a matrix may be shared between two *Mat* objects by having their matrix
|
||||
pointers point to the same address. Moreover, the copy operators **will only copy the headers** and
|
||||
the pointer to the large matrix, not the data itself.
|
||||
|
||||
@@ -74,32 +74,32 @@ Mat B(A); // Use the copy constructor
|
||||
C = A; // Assignment operator
|
||||
@endcode
|
||||
|
||||
All the above objects, in the end, point to the same single data matrix. Their headers are
|
||||
different, however, and making a modification using any of them will affect all the other ones as
|
||||
well. In practice the different objects just provide different access method to the same underlying
|
||||
data. Nevertheless, their header parts are different. The real interesting part is that you can
|
||||
create headers which refer to only a subsection of the full data. For example, to create a region of
|
||||
interest (*ROI*) in an image you just create a new header with the new boundaries:
|
||||
All the above objects, in the end, point to the same single data matrix and making a modification
|
||||
using any of them will affect all the other ones as well. In practice the different objects just
|
||||
provide different access methods to the same underlying data. Nevertheless, their header parts are
|
||||
different. The real interesting part is that you can create headers which refer to only a subsection
|
||||
of the full data. For example, to create a region of interest (*ROI*) in an image you just create
|
||||
a new header with the new boundaries:
|
||||
@code{.cpp}
|
||||
Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle
|
||||
Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries
|
||||
@endcode
|
||||
Now you may ask if the matrix itself may belong to multiple *Mat* objects who takes responsibility
|
||||
Now you may ask -- if the matrix itself may belong to multiple *Mat* objects who takes responsibility
|
||||
for cleaning it up when it's no longer needed. The short answer is: the last object that used it.
|
||||
This is handled by using a reference counting mechanism. Whenever somebody copies a header of a
|
||||
*Mat* object, a counter is increased for the matrix. Whenever a header is cleaned this counter is
|
||||
decreased. When the counter reaches zero the matrix too is freed. Sometimes you will want to copy
|
||||
the matrix itself too, so OpenCV provides the @ref cv::Mat::clone() and @ref cv::Mat::copyTo() functions.
|
||||
*Mat* object, a counter is increased for the matrix. Whenever a header is cleaned, this counter
|
||||
is decreased. When the counter reaches zero the matrix is freed. Sometimes you will want to copy
|
||||
the matrix itself too, so OpenCV provides @ref cv::Mat::clone() and @ref cv::Mat::copyTo() functions.
|
||||
@code{.cpp}
|
||||
Mat F = A.clone();
|
||||
Mat G;
|
||||
A.copyTo(G);
|
||||
@endcode
|
||||
Now modifying *F* or *G* will not affect the matrix pointed by the *Mat* header. What you need to
|
||||
Now modifying *F* or *G* will not affect the matrix pointed by the *A*'s header. What you need to
|
||||
remember from all this is that:
|
||||
|
||||
- Output image allocation for OpenCV functions is automatic (unless specified otherwise).
|
||||
- You do not need to think about memory management with OpenCVs C++ interface.
|
||||
- You do not need to think about memory management with OpenCV's C++ interface.
|
||||
- The assignment operator and the copy constructor only copies the header.
|
||||
- The underlying matrix of an image may be copied using the @ref cv::Mat::clone() and @ref cv::Mat::copyTo()
|
||||
functions.
|
||||
@@ -109,7 +109,7 @@ Storing methods
|
||||
|
||||
This is about how you store the pixel values. You can select the color space and the data type used.
|
||||
The color space refers to how we combine color components in order to code a given color. The
|
||||
simplest one is the gray scale where the colors at our disposal are black and white. The combination
|
||||
simplest one is the grayscale where the colors at our disposal are black and white. The combination
|
||||
of these allows us to create many shades of gray.
|
||||
|
||||
For *colorful* ways we have a lot more methods to choose from. Each of them breaks it down to three
|
||||
@@ -121,15 +121,15 @@ added.
|
||||
There are, however, many other color systems each with their own advantages:
|
||||
|
||||
- RGB is the most common as our eyes use something similar, however keep in mind that OpenCV standard display
|
||||
system composes colors using the BGR color space (a switch of the red and blue channel).
|
||||
system composes colors using the BGR color space (red and blue channels are swapped places).
|
||||
- The HSV and HLS decompose colors into their hue, saturation and value/luminance components,
|
||||
which is a more natural way for us to describe colors. You might, for example, dismiss the last
|
||||
component, making your algorithm less sensible to the light conditions of the input image.
|
||||
- YCrCb is used by the popular JPEG image format.
|
||||
- CIE L\*a\*b\* is a perceptually uniform color space, which comes handy if you need to measure
|
||||
- CIE L\*a\*b\* is a perceptually uniform color space, which comes in handy if you need to measure
|
||||
the *distance* of a given color to another color.
|
||||
|
||||
Each of the building components has their own valid domains. This leads to the data type used. How
|
||||
Each of the building components has its own valid domains. This leads to the data type used. How
|
||||
we store a component defines the control we have over its domain. The smallest data type possible is
|
||||
*char*, which means one byte or 8 bits. This may be unsigned (so can store values from 0 to 255) or
|
||||
signed (values from -127 to +127). Although in case of three components this already gives 16
|
||||
@@ -165,8 +165,8 @@ object in multiple ways:
|
||||
CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
|
||||
@endcode
|
||||
For instance, *CV_8UC3* means we use unsigned char types that are 8 bit long and each pixel has
|
||||
three of these to form the three channels. This are predefined for up to four channel numbers. The
|
||||
@ref cv::Scalar is four element short vector. Specify this and you can initialize all matrix
|
||||
three of these to form the three channels. There are types predefined for up to four channels. The
|
||||
@ref cv::Scalar is four element short vector. Specify it and you can initialize all matrix
|
||||
points with a custom value. If you need more you can create the type with the upper macro, setting
|
||||
the channel number in parenthesis as you can see below.
|
||||
|
||||
@@ -210,7 +210,7 @@ object in multiple ways:
|
||||
|
||||
@note
|
||||
You can fill out a matrix with random values using the @ref cv::randu() function. You need to
|
||||
give the lower and upper value for the random values:
|
||||
give a lower and upper limit for the random values:
|
||||
@snippet mat_the_basic_image_container.cpp random
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Tutorial was written for the following versions of corresponding software:
|
||||
|
||||
- Download and install Android Studio from https://developer.android.com/studio.
|
||||
|
||||
- Get the latest pre-built OpenCV for Android release from https://github.com/opencv/opencv/releases and unpack it (for example, `opencv-3.4.8-android-sdk.zip`).
|
||||
- Get the latest pre-built OpenCV for Android release from https://github.com/opencv/opencv/releases and unpack it (for example, `opencv-3.4.9-android-sdk.zip`).
|
||||
|
||||
- Download MobileNet object detection model from https://github.com/chuanqi305/MobileNet-SSD. We need a configuration file `MobileNetSSD_deploy.prototxt` and weights `MobileNetSSD_deploy.caffemodel`.
|
||||
|
||||
|
||||
@@ -210,12 +210,12 @@ Explanation
|
||||
@code{.cpp}
|
||||
image2 = image - Scalar::all(i)
|
||||
@endcode
|
||||
So, **image2** is the substraction of **image** and **Scalar::all(i)**. In fact, what happens
|
||||
here is that every pixel of **image2** will be the result of substracting every pixel of
|
||||
So, **image2** is the subtraction of **image** and **Scalar::all(i)**. In fact, what happens
|
||||
here is that every pixel of **image2** will be the result of subtracting every pixel of
|
||||
**image** minus the value of **i** (remember that for each pixel we are considering three values
|
||||
such as R, G and B, so each of them will be affected)
|
||||
|
||||
Also remember that the substraction operation *always* performs internally a **saturate**
|
||||
Also remember that the subtraction operation *always* performs internally a **saturate**
|
||||
operation, which means that the result obtained will always be inside the allowed range (no
|
||||
negative and between 0 and 255 for our example).
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Cross referencing OpenCV from other Doxygen projects {#tutorial_cross_referencin
|
||||
Cross referencing OpenCV
|
||||
------------------------
|
||||
|
||||
[Doxygen](https://www.stack.nl/~dimitri/doxygen/) is a tool to generate
|
||||
[Doxygen](http://www.doxygen.nl) is a tool to generate
|
||||
documentations like the OpenCV documentation you are reading right now.
|
||||
It is used by a variety of software projects and if you happen to use it
|
||||
to generate your own documentation, and you are using OpenCV inside your
|
||||
@@ -36,14 +36,14 @@ Open your Doxyfile using your favorite text editor and search for the key
|
||||
`TAGFILES`. Change it as follows:
|
||||
|
||||
@code
|
||||
TAGFILES = ./docs/doxygen-tags/opencv.tag=http://docs.opencv.org/3.4.8
|
||||
TAGFILES = ./docs/doxygen-tags/opencv.tag=http://docs.opencv.org/3.4.9
|
||||
@endcode
|
||||
|
||||
If you had other definitions already, you can append the line using a `\`:
|
||||
|
||||
@code
|
||||
TAGFILES = ./docs/doxygen-tags/libstdc++.tag=https://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen \
|
||||
./docs/doxygen-tags/opencv.tag=http://docs.opencv.org/3.4.8
|
||||
./docs/doxygen-tags/opencv.tag=http://docs.opencv.org/3.4.9
|
||||
@endcode
|
||||
|
||||
Doxygen can now use the information from the tag file to link to the OpenCV
|
||||
@@ -57,5 +57,5 @@ contain a `your_project.tag` file in its root directory.
|
||||
References
|
||||
----------
|
||||
|
||||
- [Doxygen: Linking to external documentation](https://www.stack.nl/~dimitri/doxygen/manual/external.html)
|
||||
- [Doxygen: Linking to external documentation](http://www.doxygen.nl/manual/external.html)
|
||||
- [opencv.tag](opencv.tag)
|
||||
|
||||
@@ -684,12 +684,12 @@ References {#tutorial_documentation_refs}
|
||||
- [Command reference] - supported commands and their parameters
|
||||
|
||||
<!-- invisible references list -->
|
||||
[Doxygen]: http://www.stack.nl/~dimitri/doxygen/index.html)
|
||||
[Doxygen download]: http://www.stack.nl/~dimitri/doxygen/download.html
|
||||
[Doxygen installation]: http://www.stack.nl/~dimitri/doxygen/manual/install.html
|
||||
[Documenting basics]: http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html
|
||||
[Markdown support]: http://www.stack.nl/~dimitri/doxygen/manual/markdown.html
|
||||
[Formulas support]: http://www.stack.nl/~dimitri/doxygen/manual/formulas.html
|
||||
[Doxygen]: http://www.doxygen.nl
|
||||
[Doxygen download]: http://doxygen.nl/download.html
|
||||
[Doxygen installation]: http://doxygen.nl/manual/install.html
|
||||
[Documenting basics]: http://www.doxygen.nl/manual/docblocks.html
|
||||
[Markdown support]: http://www.doxygen.nl/manual/markdown.html
|
||||
[Formulas support]: http://www.doxygen.nl/manual/formulas.html
|
||||
[Supported formula commands]: http://docs.mathjax.org/en/latest/tex.html#supported-latex-commands
|
||||
[Command reference]: http://www.stack.nl/~dimitri/doxygen/manual/commands.html
|
||||
[Command reference]: http://www.doxygen.nl/manual/commands.html
|
||||
[Google Scholar]: http://scholar.google.ru/
|
||||
|
||||
@@ -9,7 +9,7 @@ Required Packages
|
||||
|
||||
### Getting the Cutting-edge OpenCV from Git Repository
|
||||
|
||||
Launch GIT client and clone OpenCV repository from [here](http://github.com/opencv/opencv)
|
||||
Launch Git client and clone OpenCV repository from [GitHub](http://github.com/opencv/opencv).
|
||||
|
||||
In MacOS it can be done using the following command in Terminal:
|
||||
|
||||
@@ -18,24 +18,48 @@ cd ~/<my_working _directory>
|
||||
git clone https://github.com/opencv/opencv.git
|
||||
@endcode
|
||||
|
||||
If you want to install OpenCV’s extra modules, clone the opencv_contrib repository as well:
|
||||
|
||||
@code{.bash}
|
||||
cd ~/<my_working _directory>
|
||||
git clone https://github.com/opencv/opencv_contrib.git
|
||||
@endcode
|
||||
|
||||
|
||||
Building OpenCV from Source, using CMake and Command Line
|
||||
---------------------------------------------------------
|
||||
|
||||
-# Make symbolic link for Xcode to let OpenCV build scripts find the compiler, header files etc.
|
||||
1. Make sure the xcode command line tools are installed:
|
||||
@code{.bash}
|
||||
cd /
|
||||
sudo ln -s /Applications/Xcode.app/Contents/Developer Developer
|
||||
xcode-select --install
|
||||
@endcode
|
||||
|
||||
-# Build OpenCV framework:
|
||||
2. Build OpenCV framework:
|
||||
@code{.bash}
|
||||
cd ~/<my_working_directory>
|
||||
python opencv/platforms/ios/build_framework.py ios
|
||||
@endcode
|
||||
|
||||
If everything's fine, a few minutes later you will get
|
||||
\~/\<my_working_directory\>/ios/opencv2.framework. You can add this framework to your Xcode
|
||||
projects.
|
||||
3. To install OpenCV’s extra modules, append `--contrib opencv_contrib` to the python command above. **Note:** the extra modules are not included in the iOS Pack download at [OpenCV Releases](https://opencv.org/releases/). If you want to use the extra modules (e.g. aruco), you must build OpenCV yourself and include this option:
|
||||
@code{.bash}
|
||||
cd ~/<my_working_directory>
|
||||
python opencv/platforms/ios/build_framework.py ios --contrib opencv_contrib
|
||||
@endcode
|
||||
|
||||
4. To exclude a specific module, append `--without <module_name>`. For example, to exclude the "optflow" module from opencv_contrib:
|
||||
@code{.bash}
|
||||
cd ~/<my_working_directory>
|
||||
python opencv/platforms/ios/build_framework.py ios --contrib opencv_contrib --without optflow
|
||||
@endcode
|
||||
|
||||
5. The build process can take a significant amount of time. Currently (OpenCV 3.4 and 4.1), five separate architectures are built: armv7, armv7s, and arm64 for iOS plus i386 and x86_64 for the iPhone simulator. If you want to specify the architectures to include in the framework, use the `--iphoneos_archs` and/or `--iphonesimulator_archs` options. For example, to only build arm64 for iOS and x86_64 for the simulator:
|
||||
@code{.bash}
|
||||
cd ~/<my_working_directory>
|
||||
python opencv/platforms/ios/build_framework.py ios --contrib opencv_contrib --iphoneos_archs arm64 --iphonesimulator_archs x86_64
|
||||
@endcode
|
||||
|
||||
If everything’s fine, the build process will create
|
||||
`~/<my_working_directory>/ios/opencv2.framework`. You can add this framework to your Xcode projects.
|
||||
|
||||
Further Reading
|
||||
---------------
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
Installation in MacOS {#tutorial_macos_install}
|
||||
=====================
|
||||
|
||||
The following steps have been tested for MacOSX (Mavericks) but should work with other versions as well.
|
||||
|
||||
Required Packages
|
||||
-----------------
|
||||
|
||||
- CMake 3.9 or higher
|
||||
- Git
|
||||
- Python 2.7 or later and Numpy 1.5 or later
|
||||
|
||||
This tutorial will assume you have [Python](https://docs.python.org/3/using/mac.html),
|
||||
[Numpy](https://docs.scipy.org/doc/numpy-1.10.1/user/install.html) and
|
||||
[Git](https://www.atlassian.com/git/tutorials/install-git) installed on your machine.
|
||||
|
||||
@note
|
||||
OSX comes with Python 2.7 by default, you will need to install Python 3.8 if you want to use it specifically.
|
||||
|
||||
@note
|
||||
If you XCode and XCode Command Line-Tools installed, you already have git installed on your machine.
|
||||
|
||||
Installing CMake
|
||||
----------------
|
||||
-# Find the version for your system and download CMake from their release's [page](https://cmake.org/download/)
|
||||
|
||||
-# Install the dmg package and launch it from Applications. That will give you the UI app of CMake
|
||||
|
||||
-# From the CMake app window, choose menu Tools --> Install For Command Line Use.
|
||||
|
||||
-# Install folder will be /usr/bin/ by default, submit it by choosing Install command line links.
|
||||
|
||||
-# Test that it works by running
|
||||
@code{.bash}
|
||||
cmake --version
|
||||
@endcode
|
||||
|
||||
Getting OpenCV Source Code
|
||||
--------------------------
|
||||
|
||||
You can use the latest stable OpenCV version or you can grab the latest snapshot from our
|
||||
[Git repository](https://github.com/opencv/opencv.git).
|
||||
|
||||
### Getting the Latest Stable OpenCV Version
|
||||
|
||||
- Go to our [downloads page](http://opencv.org/releases.html).
|
||||
- Download the source archive and unpack it.
|
||||
|
||||
### Getting the Cutting-edge OpenCV from the Git Repository
|
||||
|
||||
Launch Git client and clone [OpenCV repository](http://github.com/opencv/opencv).
|
||||
If you need modules from [OpenCV contrib repository](http://github.com/opencv/opencv_contrib) then clone it as well.
|
||||
|
||||
For example
|
||||
@code{.bash}
|
||||
cd ~/<my_working_directory>
|
||||
git clone https://github.com/opencv/opencv.git
|
||||
git clone https://github.com/opencv/opencv_contrib.git
|
||||
@endcode
|
||||
Building OpenCV from Source Using CMake
|
||||
---------------------------------------
|
||||
|
||||
-# Create a temporary directory, which we denote as `<cmake_build_dir>`, where you want to put
|
||||
the generated Makefiles, project files as well the object files and output binaries and enter
|
||||
there.
|
||||
|
||||
For example
|
||||
@code{.bash}
|
||||
mkdir build_opencv
|
||||
cd build_opencv
|
||||
@endcode
|
||||
|
||||
@note It is good practice to keep clean your source code directories. Create build directory outside of source tree.
|
||||
|
||||
-# Configuring. Run `cmake [<some optional parameters>] <path to the OpenCV source directory>`
|
||||
|
||||
For example
|
||||
@code{.bash}
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON ../opencv
|
||||
@endcode
|
||||
|
||||
or cmake-gui
|
||||
|
||||
- set full path to OpenCV source code, e.g. `/home/user/opencv`
|
||||
- set full path to `<cmake_build_dir>`, e.g. `/home/user/build_opencv`
|
||||
- set optional parameters
|
||||
- run: "Configure"
|
||||
- run: "Generate"
|
||||
|
||||
-# Description of some parameters
|
||||
- build type: `CMAKE_BUILD_TYPE=Release` (or `Debug`)
|
||||
- to build with modules from opencv_contrib set `OPENCV_EXTRA_MODULES_PATH` to `<path to
|
||||
opencv_contrib>/modules`
|
||||
- set `BUILD_DOCS=ON` for building documents (doxygen is required)
|
||||
- set `BUILD_EXAMPLES=ON` to build all examples
|
||||
|
||||
-# [optional] Building python. Set the following python parameters:
|
||||
- `PYTHON3_EXECUTABLE = <path to python>`
|
||||
- `PYTHON3_INCLUDE_DIR = /usr/include/python<version>`
|
||||
- `PYTHON3_NUMPY_INCLUDE_DIRS =
|
||||
/usr/lib/python<version>/dist-packages/numpy/core/include/`
|
||||
@note
|
||||
To specify Python2 versions, you can replace `PYTHON3_` with `PYTHON2_` in the above parameters.
|
||||
|
||||
-# Build. From build directory execute *make*, it is recommended to do this in several threads
|
||||
|
||||
For example
|
||||
@code{.bash}
|
||||
make -j7 # runs 7 jobs in parallel
|
||||
@endcode
|
||||
|
||||
-# To use OpenCV in your CMake-based projects through `find_package(OpenCV)` specify `OpenCV_DIR=<path_to_build_or_install_directory>` variable.
|
||||
|
||||
@note
|
||||
You can also use a package manager like [Homebrew](https://brew.sh/)
|
||||
or [pip](https://pip.pypa.io/en/stable/) to install releases of OpenCV only (Not the cutting edge).
|
||||
@@ -110,11 +110,19 @@ Additionally you can find very basic sample source code to introduce you to the
|
||||
|
||||
Modify Android camera preview with OpenCL
|
||||
|
||||
- @subpage tutorial_macos_install
|
||||
|
||||
_Compatibility:_ \> OpenCV 3.4.x
|
||||
|
||||
_Author:_ [\@sajarindider](https://github.com/sajarindider)
|
||||
|
||||
We will learn how to setup OpenCV in MacOS.
|
||||
|
||||
- @subpage tutorial_ios_install
|
||||
|
||||
_Compatibility:_ \> OpenCV 2.4.2
|
||||
|
||||
_Author:_ Artem Myagkov, Eduard Feicho
|
||||
_Author:_ Artem Myagkov, Eduard Feicho, Steve Nicholson
|
||||
|
||||
We will learn how to setup OpenCV for using it in iOS!
|
||||
|
||||
|
||||
@@ -48,10 +48,8 @@ CMAKE_CONFIG_GENERATOR="Visual Studio 14 2015 Win64"
|
||||
if [ ! -d "$myRepo/opencv" ]; then
|
||||
echo "cloning opencv"
|
||||
git clone https://github.com/opencv/opencv.git
|
||||
mkdir Build
|
||||
mkdir Build/opencv
|
||||
mkdir Install
|
||||
mkdir Install/opencv
|
||||
mkdir -p Build/opencv
|
||||
mkdir -p Install/opencv
|
||||
else
|
||||
cd opencv
|
||||
git pull --rebase
|
||||
@@ -60,8 +58,7 @@ fi
|
||||
if [ ! -d "$myRepo/opencv_contrib" ]; then
|
||||
echo "cloning opencv_contrib"
|
||||
git clone https://github.com/opencv/opencv_contrib.git
|
||||
mkdir Build
|
||||
mkdir Build/opencv_contrib
|
||||
mkdir -p Build/opencv_contrib
|
||||
else
|
||||
cd opencv_contrib
|
||||
git pull --rebase
|
||||
@@ -154,7 +151,7 @@ of them, you need to download and install them on your system.
|
||||
image file format.
|
||||
- The OpenNI Framework contains a set of open source APIs that provide support for natural interaction with devices via methods such as voice command recognition, hand gestures, and body
|
||||
motion tracking. Prebuilt binaries can be found [here](http://structure.io/openni). The source code of [OpenNI](https://github.com/OpenNI/OpenNI) and [OpenNI2](https://github.com/OpenNI/OpenNI2) are also available on Github.
|
||||
- [Doxygen](http://www.stack.nl/~dimitri/doxygen/) is a documentation generator and is the tool that will actually create the
|
||||
- [Doxygen](http://www.doxygen.nl) is a documentation generator and is the tool that will actually create the
|
||||
*OpenCV documentation*.
|
||||
|
||||
Now we will describe the steps to follow for a full build (using all the above frameworks, tools and
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 26 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user