mirror of
https://github.com/opencv/opencv.git
synced 2026-07-25 13:23:02 +04:00
Compare commits
376 Commits
4.1.2-openvino
...
3.4.9
| 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 | |||
| 6bdb9ca725 | |||
| 1ca74c3c03 | |||
| c3a588037a | |||
| 3fd36c1be1 | |||
| 24effe8cd6 | |||
| 2ff1fb60ad | |||
| 374d952e09 | |||
| 6efdfee3f0 | |||
| 42ac089e12 | |||
| 4748aca61f | |||
| f2fe6f40c2 | |||
| 7837ae0e19 | |||
| a007220c52 | |||
| ebb77bb311 | |||
| 53400d86e2 | |||
| c0489963bb | |||
| 98fc098216 | |||
| 953c60829e | |||
| 6d811f9879 | |||
| 22d0c57a1c | |||
| b1485d0337 | |||
| bdc097495a | |||
| feff8bf972 | |||
| f301f17b61 | |||
| c13a5ce229 | |||
| ab5252c18e | |||
| e35fd463e7 | |||
| fd11e3a81d | |||
| 22d86116ee | |||
| deea46000e | |||
| c99db2b9db | |||
| c69245da1f | |||
| 2b66495a9d | |||
| a105f56957 | |||
| 23bd1866ca | |||
| 59c182ed2b | |||
| c06115cb3f | |||
| 8b483a91bc | |||
| 8814645c8d | |||
| c92f3072b4 | |||
| ffea927ac2 | |||
| 77346d7286 | |||
| 440a937d24 | |||
| ba0b3983c6 | |||
| a3144cbadc | |||
| 5c9a624a85 | |||
| d88d1c9935 | |||
| ed9bca969c | |||
| aa61e79615 | |||
| 25dee8383c | |||
| f81e401cd0 | |||
| 7ce9428e96 | |||
| 677b94c92e | |||
| b88435fdc2 | |||
| 790927bb55 | |||
| e923712d81 | |||
| eacadf0e73 | |||
| 0a1b957331 | |||
| e3daf489c8 | |||
| 1c17b3281a | |||
| d2cacac07a | |||
| e0be771b64 | |||
| c2096771cb | |||
| 3cf9185159 | |||
| c8abf2ad14 | |||
| c4d2e3c0b3 | |||
| b40fd6de32 | |||
| 3516d0835e | |||
| fcc69d5a60 | |||
| fef7fc343e | |||
| ad2854c8b3 | |||
| eabbe38001 | |||
| b1ea91d8bd | |||
| 66842f5a18 | |||
| 33e9fe9312 | |||
| 65c209fad3 | |||
| a9163a53d3 | |||
| c657c6cbac | |||
| 8167d47efc | |||
| 1ecea1f4a6 | |||
| 46fd112f9b | |||
| bcf7d3160c | |||
| d2872afce0 | |||
| 70c88a2087 | |||
| 7770ba1f10 | |||
| 7b3a752012 | |||
| 5a75808516 | |||
| 03c4c67dad | |||
| f5f9187720 | |||
| 89b82e796e | |||
| 48fa39f675 | |||
| 69c19dc3d3 | |||
| 5c0502b470 | |||
| f10fce9ab4 | |||
| aaad238c6e | |||
| 741aee6901 | |||
| 0428f60d66 | |||
| b465c82696 | |||
| 8609198b05 | |||
| bf8b5ffeb1 | |||
| a17231a6b4 | |||
| b3a0507546 | |||
| f139a0bda8 | |||
| bdf23ce855 | |||
| 6a49887695 | |||
| e7b6753a10 | |||
| 9d4f01626c | |||
| d974d4c6ce |
@@ -22,3 +22,4 @@ bin/
|
||||
*.log
|
||||
*.tlog
|
||||
build
|
||||
node_modules
|
||||
|
||||
Vendored
+5
-5
@@ -1,8 +1,8 @@
|
||||
# Binaries branch name: ffmpeg/3.4_20190612
|
||||
# Binaries were created for OpenCV: 1c661e754812d3423e8c15ccb9cdab57fc122c44
|
||||
ocv_update(FFMPEG_BINARIES_COMMIT "d284fd09e76966e95f08e1ac3a1a28b227447501")
|
||||
ocv_update(FFMPEG_FILE_HASH_BIN32 "a7032bf6cc1cb010dc055f352277792c")
|
||||
ocv_update(FFMPEG_FILE_HASH_BIN64 "40d1a38b83a0413a3fcf9df1044fff2a")
|
||||
# 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
+9
@@ -46,6 +46,15 @@ if(";${CPU_BASELINE_FINAL};" MATCHES "SSE2"
|
||||
add_definitions(-DPNG_INTEL_SSE)
|
||||
endif()
|
||||
|
||||
# set definitions and sources for MIPS
|
||||
if(";${CPU_BASELINE_FINAL};" MATCHES "MSA")
|
||||
list(APPEND lib_srcs mips/mips_init.c mips/filter_msa_intrinsics.c)
|
||||
add_definitions(-DPNG_MIPS_MSA_OPT=2)
|
||||
ocv_warnings_disable(CMAKE_C_FLAGS -Wshadow)
|
||||
else()
|
||||
add_definitions(-DPNG_MIPS_MSA_OPT=0)
|
||||
endif()
|
||||
|
||||
if(PPC64LE OR PPC64)
|
||||
# VSX3 features are backwards compatible
|
||||
if(";${CPU_BASELINE_FINAL};" MATCHES "VSX.*"
|
||||
|
||||
+808
@@ -0,0 +1,808 @@
|
||||
|
||||
/* filter_msa_intrinsics.c - MSA optimised filter functions
|
||||
*
|
||||
* Copyright (c) 2018 Cosmin Truta
|
||||
* Copyright (c) 2016 Glenn Randers-Pehrson
|
||||
* Written by Mandar Sahastrabuddhe, August 2016.
|
||||
*
|
||||
* This code is released under the libpng license.
|
||||
* For conditions of distribution and use, see the disclaimer
|
||||
* and license in png.h
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "../pngpriv.h"
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
|
||||
/* This code requires -mfpu=msa on the command line: */
|
||||
#if PNG_MIPS_MSA_IMPLEMENTATION == 1 /* intrinsics code from pngpriv.h */
|
||||
|
||||
#include <msa.h>
|
||||
|
||||
/* libpng row pointers are not necessarily aligned to any particular boundary,
|
||||
* however this code will only work with appropriate alignment. mips/mips_init.c
|
||||
* checks for this (and will not compile unless it is done). This code uses
|
||||
* variants of png_aligncast to avoid compiler warnings.
|
||||
*/
|
||||
#define png_ptr(type,pointer) png_aligncast(type *,pointer)
|
||||
#define png_ptrc(type,pointer) png_aligncastconst(const type *,pointer)
|
||||
|
||||
/* The following relies on a variable 'temp_pointer' being declared with type
|
||||
* 'type'. This is written this way just to hide the GCC strict aliasing
|
||||
* warning; note that the code is safe because there never is an alias between
|
||||
* the input and output pointers.
|
||||
*/
|
||||
#define png_ldr(type,pointer)\
|
||||
(temp_pointer = png_ptr(type,pointer), *temp_pointer)
|
||||
|
||||
#if PNG_MIPS_MSA_OPT > 0
|
||||
|
||||
#ifdef CLANG_BUILD
|
||||
#define MSA_SRLI_B(a, b) __msa_srli_b((v16i8) a, b)
|
||||
|
||||
#define LW(psrc) \
|
||||
( { \
|
||||
uint8_t *psrc_lw_m = (uint8_t *) (psrc); \
|
||||
uint32_t val_m; \
|
||||
\
|
||||
asm volatile ( \
|
||||
"lw %[val_m], %[psrc_lw_m] \n\t" \
|
||||
\
|
||||
: [val_m] "=r" (val_m) \
|
||||
: [psrc_lw_m] "m" (*psrc_lw_m) \
|
||||
); \
|
||||
\
|
||||
val_m; \
|
||||
} )
|
||||
|
||||
#define SH(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sh_m = (uint8_t *) (pdst); \
|
||||
uint16_t val_m = (val); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"sh %[val_m], %[pdst_sh_m] \n\t" \
|
||||
\
|
||||
: [pdst_sh_m] "=m" (*pdst_sh_m) \
|
||||
: [val_m] "r" (val_m) \
|
||||
); \
|
||||
}
|
||||
|
||||
#define SW(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sw_m = (uint8_t *) (pdst); \
|
||||
uint32_t val_m = (val); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"sw %[val_m], %[pdst_sw_m] \n\t" \
|
||||
\
|
||||
: [pdst_sw_m] "=m" (*pdst_sw_m) \
|
||||
: [val_m] "r" (val_m) \
|
||||
); \
|
||||
}
|
||||
|
||||
#if (__mips == 64)
|
||||
#define SD(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sd_m = (uint8_t *) (pdst); \
|
||||
uint64_t val_m = (val); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"sd %[val_m], %[pdst_sd_m] \n\t" \
|
||||
\
|
||||
: [pdst_sd_m] "=m" (*pdst_sd_m) \
|
||||
: [val_m] "r" (val_m) \
|
||||
); \
|
||||
}
|
||||
#else
|
||||
#define SD(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sd_m = (uint8_t *) (pdst); \
|
||||
uint32_t val0_m, val1_m; \
|
||||
\
|
||||
val0_m = (uint32_t) ((val) & 0x00000000FFFFFFFF); \
|
||||
val1_m = (uint32_t) (((val) >> 32) & 0x00000000FFFFFFFF); \
|
||||
\
|
||||
SW(val0_m, pdst_sd_m); \
|
||||
SW(val1_m, pdst_sd_m + 4); \
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#define MSA_SRLI_B(a, b) (a >> b)
|
||||
|
||||
#if (__mips_isa_rev >= 6)
|
||||
#define LW(psrc) \
|
||||
( { \
|
||||
uint8_t *psrc_lw_m = (uint8_t *) (psrc); \
|
||||
uint32_t val_m; \
|
||||
\
|
||||
asm volatile ( \
|
||||
"lw %[val_m], %[psrc_lw_m] \n\t" \
|
||||
\
|
||||
: [val_m] "=r" (val_m) \
|
||||
: [psrc_lw_m] "m" (*psrc_lw_m) \
|
||||
); \
|
||||
\
|
||||
val_m; \
|
||||
} )
|
||||
|
||||
#define SH(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sh_m = (uint8_t *) (pdst); \
|
||||
uint16_t val_m = (val); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"sh %[val_m], %[pdst_sh_m] \n\t" \
|
||||
\
|
||||
: [pdst_sh_m] "=m" (*pdst_sh_m) \
|
||||
: [val_m] "r" (val_m) \
|
||||
); \
|
||||
}
|
||||
|
||||
#define SW(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sw_m = (uint8_t *) (pdst); \
|
||||
uint32_t val_m = (val); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"sw %[val_m], %[pdst_sw_m] \n\t" \
|
||||
\
|
||||
: [pdst_sw_m] "=m" (*pdst_sw_m) \
|
||||
: [val_m] "r" (val_m) \
|
||||
); \
|
||||
}
|
||||
|
||||
#if (__mips == 64)
|
||||
#define SD(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sd_m = (uint8_t *) (pdst); \
|
||||
uint64_t val_m = (val); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"sd %[val_m], %[pdst_sd_m] \n\t" \
|
||||
\
|
||||
: [pdst_sd_m] "=m" (*pdst_sd_m) \
|
||||
: [val_m] "r" (val_m) \
|
||||
); \
|
||||
}
|
||||
#else
|
||||
#define SD(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sd_m = (uint8_t *) (pdst); \
|
||||
uint32_t val0_m, val1_m; \
|
||||
\
|
||||
val0_m = (uint32_t) ((val) & 0x00000000FFFFFFFF); \
|
||||
val1_m = (uint32_t) (((val) >> 32) & 0x00000000FFFFFFFF); \
|
||||
\
|
||||
SW(val0_m, pdst_sd_m); \
|
||||
SW(val1_m, pdst_sd_m + 4); \
|
||||
}
|
||||
#endif
|
||||
#else // !(__mips_isa_rev >= 6)
|
||||
#define LW(psrc) \
|
||||
( { \
|
||||
uint8_t *psrc_lw_m = (uint8_t *) (psrc); \
|
||||
uint32_t val_m; \
|
||||
\
|
||||
asm volatile ( \
|
||||
"ulw %[val_m], %[psrc_lw_m] \n\t" \
|
||||
\
|
||||
: [val_m] "=r" (val_m) \
|
||||
: [psrc_lw_m] "m" (*psrc_lw_m) \
|
||||
); \
|
||||
\
|
||||
val_m; \
|
||||
} )
|
||||
|
||||
#define SH(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sh_m = (uint8_t *) (pdst); \
|
||||
uint16_t val_m = (val); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"ush %[val_m], %[pdst_sh_m] \n\t" \
|
||||
\
|
||||
: [pdst_sh_m] "=m" (*pdst_sh_m) \
|
||||
: [val_m] "r" (val_m) \
|
||||
); \
|
||||
}
|
||||
|
||||
#define SW(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sw_m = (uint8_t *) (pdst); \
|
||||
uint32_t val_m = (val); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"usw %[val_m], %[pdst_sw_m] \n\t" \
|
||||
\
|
||||
: [pdst_sw_m] "=m" (*pdst_sw_m) \
|
||||
: [val_m] "r" (val_m) \
|
||||
); \
|
||||
}
|
||||
|
||||
#define SD(val, pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_sd_m = (uint8_t *) (pdst); \
|
||||
uint32_t val0_m, val1_m; \
|
||||
\
|
||||
val0_m = (uint32_t) ((val) & 0x00000000FFFFFFFF); \
|
||||
val1_m = (uint32_t) (((val) >> 32) & 0x00000000FFFFFFFF); \
|
||||
\
|
||||
SW(val0_m, pdst_sd_m); \
|
||||
SW(val1_m, pdst_sd_m + 4); \
|
||||
}
|
||||
|
||||
#define SW_ZERO(pdst) \
|
||||
{ \
|
||||
uint8_t *pdst_m = (uint8_t *) (pdst); \
|
||||
\
|
||||
asm volatile ( \
|
||||
"usw $0, %[pdst_m] \n\t" \
|
||||
\
|
||||
: [pdst_m] "=m" (*pdst_m) \
|
||||
: \
|
||||
); \
|
||||
}
|
||||
#endif // (__mips_isa_rev >= 6)
|
||||
#endif
|
||||
|
||||
#define LD_B(RTYPE, psrc) *((RTYPE *) (psrc))
|
||||
#define LD_UB(...) LD_B(v16u8, __VA_ARGS__)
|
||||
#define LD_B2(RTYPE, psrc, stride, out0, out1) \
|
||||
{ \
|
||||
out0 = LD_B(RTYPE, (psrc)); \
|
||||
out1 = LD_B(RTYPE, (psrc) + stride); \
|
||||
}
|
||||
#define LD_UB2(...) LD_B2(v16u8, __VA_ARGS__)
|
||||
#define LD_B4(RTYPE, psrc, stride, out0, out1, out2, out3) \
|
||||
{ \
|
||||
LD_B2(RTYPE, (psrc), stride, out0, out1); \
|
||||
LD_B2(RTYPE, (psrc) + 2 * stride , stride, out2, out3); \
|
||||
}
|
||||
#define LD_UB4(...) LD_B4(v16u8, __VA_ARGS__)
|
||||
|
||||
#define ST_B(RTYPE, in, pdst) *((RTYPE *) (pdst)) = (in)
|
||||
#define ST_UB(...) ST_B(v16u8, __VA_ARGS__)
|
||||
#define ST_B2(RTYPE, in0, in1, pdst, stride) \
|
||||
{ \
|
||||
ST_B(RTYPE, in0, (pdst)); \
|
||||
ST_B(RTYPE, in1, (pdst) + stride); \
|
||||
}
|
||||
#define ST_UB2(...) ST_B2(v16u8, __VA_ARGS__)
|
||||
#define ST_B4(RTYPE, in0, in1, in2, in3, pdst, stride) \
|
||||
{ \
|
||||
ST_B2(RTYPE, in0, in1, (pdst), stride); \
|
||||
ST_B2(RTYPE, in2, in3, (pdst) + 2 * stride, stride); \
|
||||
}
|
||||
#define ST_UB4(...) ST_B4(v16u8, __VA_ARGS__)
|
||||
|
||||
#define ADD2(in0, in1, in2, in3, out0, out1) \
|
||||
{ \
|
||||
out0 = in0 + in1; \
|
||||
out1 = in2 + in3; \
|
||||
}
|
||||
#define ADD3(in0, in1, in2, in3, in4, in5, \
|
||||
out0, out1, out2) \
|
||||
{ \
|
||||
ADD2(in0, in1, in2, in3, out0, out1); \
|
||||
out2 = in4 + in5; \
|
||||
}
|
||||
#define ADD4(in0, in1, in2, in3, in4, in5, in6, in7, \
|
||||
out0, out1, out2, out3) \
|
||||
{ \
|
||||
ADD2(in0, in1, in2, in3, out0, out1); \
|
||||
ADD2(in4, in5, in6, in7, out2, out3); \
|
||||
}
|
||||
|
||||
#define ILVR_B2(RTYPE, in0, in1, in2, in3, out0, out1) \
|
||||
{ \
|
||||
out0 = (RTYPE) __msa_ilvr_b((v16i8) in0, (v16i8) in1); \
|
||||
out1 = (RTYPE) __msa_ilvr_b((v16i8) in2, (v16i8) in3); \
|
||||
}
|
||||
#define ILVR_B2_SH(...) ILVR_B2(v8i16, __VA_ARGS__)
|
||||
|
||||
#define HSUB_UB2(RTYPE, in0, in1, out0, out1) \
|
||||
{ \
|
||||
out0 = (RTYPE) __msa_hsub_u_h((v16u8) in0, (v16u8) in0); \
|
||||
out1 = (RTYPE) __msa_hsub_u_h((v16u8) in1, (v16u8) in1); \
|
||||
}
|
||||
#define HSUB_UB2_SH(...) HSUB_UB2(v8i16, __VA_ARGS__)
|
||||
|
||||
#define SLDI_B2_0(RTYPE, in0, in1, out0, out1, slide_val) \
|
||||
{ \
|
||||
v16i8 zero_m = { 0 }; \
|
||||
out0 = (RTYPE) __msa_sldi_b((v16i8) zero_m, (v16i8) in0, slide_val); \
|
||||
out1 = (RTYPE) __msa_sldi_b((v16i8) zero_m, (v16i8) in1, slide_val); \
|
||||
}
|
||||
#define SLDI_B2_0_UB(...) SLDI_B2_0(v16u8, __VA_ARGS__)
|
||||
|
||||
#define SLDI_B3_0(RTYPE, in0, in1, in2, out0, out1, out2, slide_val) \
|
||||
{ \
|
||||
v16i8 zero_m = { 0 }; \
|
||||
SLDI_B2_0(RTYPE, in0, in1, out0, out1, slide_val); \
|
||||
out2 = (RTYPE) __msa_sldi_b((v16i8) zero_m, (v16i8) in2, slide_val); \
|
||||
}
|
||||
#define SLDI_B3_0_UB(...) SLDI_B3_0(v16u8, __VA_ARGS__)
|
||||
|
||||
#define ILVEV_W2(RTYPE, in0, in1, in2, in3, out0, out1) \
|
||||
{ \
|
||||
out0 = (RTYPE) __msa_ilvev_w((v4i32) in1, (v4i32) in0); \
|
||||
out1 = (RTYPE) __msa_ilvev_w((v4i32) in3, (v4i32) in2); \
|
||||
}
|
||||
#define ILVEV_W2_UB(...) ILVEV_W2(v16u8, __VA_ARGS__)
|
||||
|
||||
#define ADD_ABS_H3(RTYPE, in0, in1, in2, out0, out1, out2) \
|
||||
{ \
|
||||
RTYPE zero = {0}; \
|
||||
\
|
||||
out0 = __msa_add_a_h((v8i16) zero, in0); \
|
||||
out1 = __msa_add_a_h((v8i16) zero, in1); \
|
||||
out2 = __msa_add_a_h((v8i16) zero, in2); \
|
||||
}
|
||||
#define ADD_ABS_H3_SH(...) ADD_ABS_H3(v8i16, __VA_ARGS__)
|
||||
|
||||
#define VSHF_B2(RTYPE, in0, in1, in2, in3, mask0, mask1, out0, out1) \
|
||||
{ \
|
||||
out0 = (RTYPE) __msa_vshf_b((v16i8) mask0, (v16i8) in1, (v16i8) in0); \
|
||||
out1 = (RTYPE) __msa_vshf_b((v16i8) mask1, (v16i8) in3, (v16i8) in2); \
|
||||
}
|
||||
#define VSHF_B2_UB(...) VSHF_B2(v16u8, __VA_ARGS__)
|
||||
|
||||
#define CMP_AND_SELECT(inp0, inp1, inp2, inp3, inp4, inp5, out0) \
|
||||
{ \
|
||||
v8i16 _sel_h0, _sel_h1; \
|
||||
v16u8 _sel_b0, _sel_b1; \
|
||||
_sel_h0 = (v8i16) __msa_clt_u_h((v8u16) inp1, (v8u16) inp0); \
|
||||
_sel_b0 = (v16u8) __msa_pckev_b((v16i8) _sel_h0, (v16i8) _sel_h0); \
|
||||
inp0 = (v8i16) __msa_bmnz_v((v16u8) inp0, (v16u8) inp1, (v16u8) _sel_h0); \
|
||||
inp4 = (v16u8) __msa_bmnz_v(inp3, inp4, _sel_b0); \
|
||||
_sel_h1 = (v8i16) __msa_clt_u_h((v8u16) inp2, (v8u16) inp0); \
|
||||
_sel_b1 = (v16u8) __msa_pckev_b((v16i8) _sel_h1, (v16i8) _sel_h1); \
|
||||
inp4 = (v16u8) __msa_bmnz_v(inp4, inp5, _sel_b1); \
|
||||
out0 += inp4; \
|
||||
}
|
||||
|
||||
void png_read_filter_row_up_msa(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t i, cnt, cnt16, cnt32;
|
||||
size_t istop = row_info->rowbytes;
|
||||
png_bytep rp = row;
|
||||
png_const_bytep pp = prev_row;
|
||||
v16u8 src0, src1, src2, src3, src4, src5, src6, src7;
|
||||
|
||||
for (i = 0; i < (istop >> 6); i++)
|
||||
{
|
||||
LD_UB4(rp, 16, src0, src1, src2, src3);
|
||||
LD_UB4(pp, 16, src4, src5, src6, src7);
|
||||
pp += 64;
|
||||
|
||||
ADD4(src0, src4, src1, src5, src2, src6, src3, src7,
|
||||
src0, src1, src2, src3);
|
||||
|
||||
ST_UB4(src0, src1, src2, src3, rp, 16);
|
||||
rp += 64;
|
||||
}
|
||||
|
||||
if (istop & 0x3F)
|
||||
{
|
||||
cnt32 = istop & 0x20;
|
||||
cnt16 = istop & 0x10;
|
||||
cnt = istop & 0xF;
|
||||
|
||||
if(cnt32)
|
||||
{
|
||||
if (cnt16 && cnt)
|
||||
{
|
||||
LD_UB4(rp, 16, src0, src1, src2, src3);
|
||||
LD_UB4(pp, 16, src4, src5, src6, src7);
|
||||
|
||||
ADD4(src0, src4, src1, src5, src2, src6, src3, src7,
|
||||
src0, src1, src2, src3);
|
||||
|
||||
ST_UB4(src0, src1, src2, src3, rp, 16);
|
||||
rp += 64;
|
||||
}
|
||||
else if (cnt16 || cnt)
|
||||
{
|
||||
LD_UB2(rp, 16, src0, src1);
|
||||
LD_UB2(pp, 16, src4, src5);
|
||||
pp += 32;
|
||||
src2 = LD_UB(rp + 32);
|
||||
src6 = LD_UB(pp);
|
||||
|
||||
ADD3(src0, src4, src1, src5, src2, src6, src0, src1, src2);
|
||||
|
||||
ST_UB2(src0, src1, rp, 16);
|
||||
rp += 32;
|
||||
ST_UB(src2, rp);
|
||||
rp += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
LD_UB2(rp, 16, src0, src1);
|
||||
LD_UB2(pp, 16, src4, src5);
|
||||
|
||||
ADD2(src0, src4, src1, src5, src0, src1);
|
||||
|
||||
ST_UB2(src0, src1, rp, 16);
|
||||
rp += 32;
|
||||
}
|
||||
}
|
||||
else if (cnt16 && cnt)
|
||||
{
|
||||
LD_UB2(rp, 16, src0, src1);
|
||||
LD_UB2(pp, 16, src4, src5);
|
||||
|
||||
ADD2(src0, src4, src1, src5, src0, src1);
|
||||
|
||||
ST_UB2(src0, src1, rp, 16);
|
||||
rp += 32;
|
||||
}
|
||||
else if (cnt16 || cnt)
|
||||
{
|
||||
src0 = LD_UB(rp);
|
||||
src4 = LD_UB(pp);
|
||||
pp += 16;
|
||||
|
||||
src0 += src4;
|
||||
|
||||
ST_UB(src0, rp);
|
||||
rp += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void png_read_filter_row_sub4_msa(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t count;
|
||||
size_t istop = row_info->rowbytes;
|
||||
png_bytep src = row;
|
||||
png_bytep nxt = row + 4;
|
||||
int32_t inp0;
|
||||
v16u8 src0, src1, src2, src3, src4;
|
||||
v16u8 dst0, dst1;
|
||||
v16u8 zero = { 0 };
|
||||
|
||||
istop -= 4;
|
||||
|
||||
inp0 = LW(src);
|
||||
src += 4;
|
||||
src0 = (v16u8) __msa_insert_w((v4i32) zero, 0, inp0);
|
||||
|
||||
for (count = 0; count < istop; count += 16)
|
||||
{
|
||||
src1 = LD_UB(src);
|
||||
src += 16;
|
||||
|
||||
src2 = (v16u8) __msa_sldi_b((v16i8) zero, (v16i8) src1, 4);
|
||||
src3 = (v16u8) __msa_sldi_b((v16i8) zero, (v16i8) src1, 8);
|
||||
src4 = (v16u8) __msa_sldi_b((v16i8) zero, (v16i8) src1, 12);
|
||||
src1 += src0;
|
||||
src2 += src1;
|
||||
src3 += src2;
|
||||
src4 += src3;
|
||||
src0 = src4;
|
||||
ILVEV_W2_UB(src1, src2, src3, src4, dst0, dst1);
|
||||
dst0 = (v16u8) __msa_pckev_d((v2i64) dst1, (v2i64) dst0);
|
||||
|
||||
ST_UB(dst0, nxt);
|
||||
nxt += 16;
|
||||
}
|
||||
}
|
||||
|
||||
void png_read_filter_row_sub3_msa(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t count;
|
||||
size_t istop = row_info->rowbytes;
|
||||
png_bytep src = row;
|
||||
png_bytep nxt = row + 3;
|
||||
int64_t out0;
|
||||
int32_t inp0, out1;
|
||||
v16u8 src0, src1, src2, src3, src4, dst0, dst1;
|
||||
v16u8 zero = { 0 };
|
||||
v16i8 mask0 = { 0, 1, 2, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
v16i8 mask1 = { 0, 1, 2, 3, 4, 5, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0 };
|
||||
|
||||
istop -= 3;
|
||||
|
||||
inp0 = LW(src);
|
||||
src += 3;
|
||||
src0 = (v16u8) __msa_insert_w((v4i32) zero, 0, inp0);
|
||||
|
||||
for (count = 0; count < istop; count += 12)
|
||||
{
|
||||
src1 = LD_UB(src);
|
||||
src += 12;
|
||||
|
||||
src2 = (v16u8) __msa_sldi_b((v16i8) zero, (v16i8) src1, 3);
|
||||
src3 = (v16u8) __msa_sldi_b((v16i8) zero, (v16i8) src1, 6);
|
||||
src4 = (v16u8) __msa_sldi_b((v16i8) zero, (v16i8) src1, 9);
|
||||
src1 += src0;
|
||||
src2 += src1;
|
||||
src3 += src2;
|
||||
src4 += src3;
|
||||
src0 = src4;
|
||||
VSHF_B2_UB(src1, src2, src3, src4, mask0, mask0, dst0, dst1);
|
||||
dst0 = (v16u8) __msa_vshf_b(mask1, (v16i8) dst1, (v16i8) dst0);
|
||||
out0 = __msa_copy_s_d((v2i64) dst0, 0);
|
||||
out1 = __msa_copy_s_w((v4i32) dst0, 2);
|
||||
|
||||
SD(out0, nxt);
|
||||
nxt += 8;
|
||||
SW(out1, nxt);
|
||||
nxt += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void png_read_filter_row_avg4_msa(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t i;
|
||||
png_bytep src = row;
|
||||
png_bytep nxt = row;
|
||||
png_const_bytep pp = prev_row;
|
||||
size_t istop = row_info->rowbytes - 4;
|
||||
int32_t inp0, inp1, out0;
|
||||
v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, dst0, dst1;
|
||||
v16u8 zero = { 0 };
|
||||
|
||||
inp0 = LW(pp);
|
||||
pp += 4;
|
||||
inp1 = LW(src);
|
||||
src += 4;
|
||||
src0 = (v16u8) __msa_insert_w((v4i32) zero, 0, inp0);
|
||||
src1 = (v16u8) __msa_insert_w((v4i32) zero, 0, inp1);
|
||||
src0 = (v16u8) MSA_SRLI_B(src0, 1);
|
||||
src1 += src0;
|
||||
out0 = __msa_copy_s_w((v4i32) src1, 0);
|
||||
SW(out0, nxt);
|
||||
nxt += 4;
|
||||
|
||||
for (i = 0; i < istop; i += 16)
|
||||
{
|
||||
src2 = LD_UB(pp);
|
||||
pp += 16;
|
||||
src6 = LD_UB(src);
|
||||
src += 16;
|
||||
|
||||
SLDI_B2_0_UB(src2, src6, src3, src7, 4);
|
||||
SLDI_B2_0_UB(src2, src6, src4, src8, 8);
|
||||
SLDI_B2_0_UB(src2, src6, src5, src9, 12);
|
||||
src2 = __msa_ave_u_b(src2, src1);
|
||||
src6 += src2;
|
||||
src3 = __msa_ave_u_b(src3, src6);
|
||||
src7 += src3;
|
||||
src4 = __msa_ave_u_b(src4, src7);
|
||||
src8 += src4;
|
||||
src5 = __msa_ave_u_b(src5, src8);
|
||||
src9 += src5;
|
||||
src1 = src9;
|
||||
ILVEV_W2_UB(src6, src7, src8, src9, dst0, dst1);
|
||||
dst0 = (v16u8) __msa_pckev_d((v2i64) dst1, (v2i64) dst0);
|
||||
|
||||
ST_UB(dst0, nxt);
|
||||
nxt += 16;
|
||||
}
|
||||
}
|
||||
|
||||
void png_read_filter_row_avg3_msa(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t i;
|
||||
png_bytep src = row;
|
||||
png_bytep nxt = row;
|
||||
png_const_bytep pp = prev_row;
|
||||
size_t istop = row_info->rowbytes - 3;
|
||||
int64_t out0;
|
||||
int32_t inp0, inp1, out1;
|
||||
int16_t out2;
|
||||
v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, dst0, dst1;
|
||||
v16u8 zero = { 0 };
|
||||
v16i8 mask0 = { 0, 1, 2, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
v16i8 mask1 = { 0, 1, 2, 3, 4, 5, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0 };
|
||||
|
||||
inp0 = LW(pp);
|
||||
pp += 3;
|
||||
inp1 = LW(src);
|
||||
src += 3;
|
||||
src0 = (v16u8) __msa_insert_w((v4i32) zero, 0, inp0);
|
||||
src1 = (v16u8) __msa_insert_w((v4i32) zero, 0, inp1);
|
||||
src0 = (v16u8) MSA_SRLI_B(src0, 1);
|
||||
src1 += src0;
|
||||
out2 = __msa_copy_s_h((v8i16) src1, 0);
|
||||
SH(out2, nxt);
|
||||
nxt += 2;
|
||||
nxt[0] = src1[2];
|
||||
nxt++;
|
||||
|
||||
for (i = 0; i < istop; i += 12)
|
||||
{
|
||||
src2 = LD_UB(pp);
|
||||
pp += 12;
|
||||
src6 = LD_UB(src);
|
||||
src += 12;
|
||||
|
||||
SLDI_B2_0_UB(src2, src6, src3, src7, 3);
|
||||
SLDI_B2_0_UB(src2, src6, src4, src8, 6);
|
||||
SLDI_B2_0_UB(src2, src6, src5, src9, 9);
|
||||
src2 = __msa_ave_u_b(src2, src1);
|
||||
src6 += src2;
|
||||
src3 = __msa_ave_u_b(src3, src6);
|
||||
src7 += src3;
|
||||
src4 = __msa_ave_u_b(src4, src7);
|
||||
src8 += src4;
|
||||
src5 = __msa_ave_u_b(src5, src8);
|
||||
src9 += src5;
|
||||
src1 = src9;
|
||||
VSHF_B2_UB(src6, src7, src8, src9, mask0, mask0, dst0, dst1);
|
||||
dst0 = (v16u8) __msa_vshf_b(mask1, (v16i8) dst1, (v16i8) dst0);
|
||||
out0 = __msa_copy_s_d((v2i64) dst0, 0);
|
||||
out1 = __msa_copy_s_w((v4i32) dst0, 2);
|
||||
|
||||
SD(out0, nxt);
|
||||
nxt += 8;
|
||||
SW(out1, nxt);
|
||||
nxt += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void png_read_filter_row_paeth4_msa(png_row_infop row_info,
|
||||
png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
int32_t count, rp_end;
|
||||
png_bytep nxt;
|
||||
png_const_bytep prev_nxt;
|
||||
int32_t inp0, inp1, res0;
|
||||
v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9;
|
||||
v16u8 src10, src11, src12, src13, dst0, dst1;
|
||||
v8i16 vec0, vec1, vec2;
|
||||
v16u8 zero = { 0 };
|
||||
|
||||
nxt = row;
|
||||
prev_nxt = prev_row;
|
||||
|
||||
inp0 = LW(nxt);
|
||||
inp1 = LW(prev_nxt);
|
||||
prev_nxt += 4;
|
||||
src0 = (v16u8) __msa_insert_w((v4i32) zero, 0, inp0);
|
||||
src1 = (v16u8) __msa_insert_w((v4i32) zero, 0, inp1);
|
||||
|
||||
src1 += src0;
|
||||
res0 = __msa_copy_s_w((v4i32) src1, 0);
|
||||
|
||||
SW(res0, nxt);
|
||||
nxt += 4;
|
||||
|
||||
/* Remainder */
|
||||
rp_end = row_info->rowbytes - 4;
|
||||
|
||||
for (count = 0; count < rp_end; count += 16)
|
||||
{
|
||||
src2 = LD_UB(prev_nxt);
|
||||
prev_nxt += 16;
|
||||
src6 = LD_UB(prev_row);
|
||||
prev_row += 16;
|
||||
src10 = LD_UB(nxt);
|
||||
|
||||
SLDI_B3_0_UB(src2, src6, src10, src3, src7, src11, 4);
|
||||
SLDI_B3_0_UB(src2, src6, src10, src4, src8, src12, 8);
|
||||
SLDI_B3_0_UB(src2, src6, src10, src5, src9, src13, 12);
|
||||
ILVR_B2_SH(src2, src6, src1, src6, vec0, vec1);
|
||||
HSUB_UB2_SH(vec0, vec1, vec0, vec1);
|
||||
vec2 = vec0 + vec1;
|
||||
ADD_ABS_H3_SH(vec0, vec1, vec2, vec0, vec1, vec2);
|
||||
CMP_AND_SELECT(vec0, vec1, vec2, src1, src2, src6, src10);
|
||||
ILVR_B2_SH(src3, src7, src10, src7, vec0, vec1);
|
||||
HSUB_UB2_SH(vec0, vec1, vec0, vec1);
|
||||
vec2 = vec0 + vec1;
|
||||
ADD_ABS_H3_SH(vec0, vec1, vec2, vec0, vec1, vec2);
|
||||
CMP_AND_SELECT(vec0, vec1, vec2, src10, src3, src7, src11);
|
||||
ILVR_B2_SH(src4, src8, src11, src8, vec0, vec1);
|
||||
HSUB_UB2_SH(vec0, vec1, vec0, vec1);
|
||||
vec2 = vec0 + vec1;
|
||||
ADD_ABS_H3_SH(vec0, vec1, vec2, vec0, vec1, vec2);
|
||||
CMP_AND_SELECT(vec0, vec1, vec2, src11, src4, src8, src12);
|
||||
ILVR_B2_SH(src5, src9, src12, src9, vec0, vec1);
|
||||
HSUB_UB2_SH(vec0, vec1, vec0, vec1);
|
||||
vec2 = vec0 + vec1;
|
||||
ADD_ABS_H3_SH(vec0, vec1, vec2, vec0, vec1, vec2);
|
||||
CMP_AND_SELECT(vec0, vec1, vec2, src12, src5, src9, src13);
|
||||
src1 = src13;
|
||||
ILVEV_W2_UB(src10, src11, src12, src1, dst0, dst1);
|
||||
dst0 = (v16u8) __msa_pckev_d((v2i64) dst1, (v2i64) dst0);
|
||||
|
||||
ST_UB(dst0, nxt);
|
||||
nxt += 16;
|
||||
}
|
||||
}
|
||||
|
||||
void png_read_filter_row_paeth3_msa(png_row_infop row_info,
|
||||
png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
int32_t count, rp_end;
|
||||
png_bytep nxt;
|
||||
png_const_bytep prev_nxt;
|
||||
int64_t out0;
|
||||
int32_t inp0, inp1, out1;
|
||||
int16_t out2;
|
||||
v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, dst0, dst1;
|
||||
v16u8 src10, src11, src12, src13;
|
||||
v8i16 vec0, vec1, vec2;
|
||||
v16u8 zero = { 0 };
|
||||
v16i8 mask0 = { 0, 1, 2, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
v16i8 mask1 = { 0, 1, 2, 3, 4, 5, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0 };
|
||||
|
||||
nxt = row;
|
||||
prev_nxt = prev_row;
|
||||
|
||||
inp0 = LW(nxt);
|
||||
inp1 = LW(prev_nxt);
|
||||
prev_nxt += 3;
|
||||
src0 = (v16u8) __msa_insert_w((v4i32) zero, 0, inp0);
|
||||
src1 = (v16u8) __msa_insert_w((v4i32) zero, 0, inp1);
|
||||
|
||||
src1 += src0;
|
||||
out2 = __msa_copy_s_h((v8i16) src1, 0);
|
||||
|
||||
SH(out2, nxt);
|
||||
nxt += 2;
|
||||
nxt[0] = src1[2];
|
||||
nxt++;
|
||||
|
||||
/* Remainder */
|
||||
rp_end = row_info->rowbytes - 3;
|
||||
|
||||
for (count = 0; count < rp_end; count += 12)
|
||||
{
|
||||
src2 = LD_UB(prev_nxt);
|
||||
prev_nxt += 12;
|
||||
src6 = LD_UB(prev_row);
|
||||
prev_row += 12;
|
||||
src10 = LD_UB(nxt);
|
||||
|
||||
SLDI_B3_0_UB(src2, src6, src10, src3, src7, src11, 3);
|
||||
SLDI_B3_0_UB(src2, src6, src10, src4, src8, src12, 6);
|
||||
SLDI_B3_0_UB(src2, src6, src10, src5, src9, src13, 9);
|
||||
ILVR_B2_SH(src2, src6, src1, src6, vec0, vec1);
|
||||
HSUB_UB2_SH(vec0, vec1, vec0, vec1);
|
||||
vec2 = vec0 + vec1;
|
||||
ADD_ABS_H3_SH(vec0, vec1, vec2, vec0, vec1, vec2);
|
||||
CMP_AND_SELECT(vec0, vec1, vec2, src1, src2, src6, src10);
|
||||
ILVR_B2_SH(src3, src7, src10, src7, vec0, vec1);
|
||||
HSUB_UB2_SH(vec0, vec1, vec0, vec1);
|
||||
vec2 = vec0 + vec1;
|
||||
ADD_ABS_H3_SH(vec0, vec1, vec2, vec0, vec1, vec2);
|
||||
CMP_AND_SELECT(vec0, vec1, vec2, src10, src3, src7, src11);
|
||||
ILVR_B2_SH(src4, src8, src11, src8, vec0, vec1);
|
||||
HSUB_UB2_SH(vec0, vec1, vec0, vec1);
|
||||
vec2 = vec0 + vec1;
|
||||
ADD_ABS_H3_SH(vec0, vec1, vec2, vec0, vec1, vec2);
|
||||
CMP_AND_SELECT(vec0, vec1, vec2, src11, src4, src8, src12);
|
||||
ILVR_B2_SH(src5, src9, src12, src9, vec0, vec1);
|
||||
HSUB_UB2_SH(vec0, vec1, vec0, vec1);
|
||||
vec2 = vec0 + vec1;
|
||||
ADD_ABS_H3_SH(vec0, vec1, vec2, vec0, vec1, vec2);
|
||||
CMP_AND_SELECT(vec0, vec1, vec2, src12, src5, src9, src13);
|
||||
src1 = src13;
|
||||
VSHF_B2_UB(src10, src11, src12, src13, mask0, mask0, dst0, dst1);
|
||||
dst0 = (v16u8) __msa_vshf_b(mask1, (v16i8) dst1, (v16i8) dst0);
|
||||
out0 = __msa_copy_s_d((v2i64) dst0, 0);
|
||||
out1 = __msa_copy_s_w((v4i32) dst0, 2);
|
||||
|
||||
SD(out0, nxt);
|
||||
nxt += 8;
|
||||
SW(out1, nxt);
|
||||
nxt += 4;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* PNG_MIPS_MSA_OPT > 0 */
|
||||
#endif /* PNG_MIPS_MSA_IMPLEMENTATION == 1 (intrinsics) */
|
||||
#endif /* READ */
|
||||
Vendored
+127
@@ -0,0 +1,127 @@
|
||||
|
||||
/* mips_init.c - MSA optimised filter functions
|
||||
*
|
||||
* Copyright (c) 2018 Cosmin Truta
|
||||
* Copyright (c) 2016 Glenn Randers-Pehrson
|
||||
* Written by Mandar Sahastrabuddhe, 2016.
|
||||
*
|
||||
* This code is released under the libpng license.
|
||||
* For conditions of distribution and use, see the disclaimer
|
||||
* and license in png.h
|
||||
*/
|
||||
|
||||
/* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are
|
||||
* called.
|
||||
*/
|
||||
#define _POSIX_SOURCE 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../pngpriv.h"
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
|
||||
#if PNG_MIPS_MSA_OPT > 0
|
||||
#ifdef PNG_MIPS_MSA_CHECK_SUPPORTED /* Do run-time checks */
|
||||
/* WARNING: it is strongly recommended that you do not build libpng with
|
||||
* run-time checks for CPU features if at all possible. In the case of the MIPS
|
||||
* MSA instructions there is no processor-specific way of detecting the
|
||||
* presence of the required support, therefore run-time detection is extremely
|
||||
* OS specific.
|
||||
*
|
||||
* You may set the macro PNG_MIPS_MSA_FILE to the file name of file containing
|
||||
* a fragment of C source code which defines the png_have_msa function. There
|
||||
* are a number of implementations in contrib/mips-msa, but the only one that
|
||||
* has partial support is contrib/mips-msa/linux.c - a generic Linux
|
||||
* implementation which reads /proc/cpufino.
|
||||
*/
|
||||
#ifndef PNG_MIPS_MSA_FILE
|
||||
# ifdef __linux__
|
||||
# define PNG_MIPS_MSA_FILE "contrib/mips-msa/linux.c"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PNG_MIPS_MSA_FILE
|
||||
|
||||
#include <signal.h> /* for sig_atomic_t */
|
||||
static int png_have_msa(png_structp png_ptr);
|
||||
#include PNG_MIPS_MSA_FILE
|
||||
|
||||
#else /* PNG_MIPS_MSA_FILE */
|
||||
# error "PNG_MIPS_MSA_FILE undefined: no support for run-time MIPS MSA checks"
|
||||
#endif /* PNG_MIPS_MSA_FILE */
|
||||
#endif /* PNG_MIPS_MSA_CHECK_SUPPORTED */
|
||||
|
||||
#ifndef PNG_ALIGNED_MEMORY_SUPPORTED
|
||||
# error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED"
|
||||
#endif
|
||||
|
||||
void
|
||||
png_init_filter_functions_msa(png_structp pp, unsigned int bpp)
|
||||
{
|
||||
/* The switch statement is compiled in for MIPS_MSA_API, the call to
|
||||
* png_have_msa is compiled in for MIPS_MSA_CHECK. If both are defined
|
||||
* the check is only performed if the API has not set the MSA option on
|
||||
* or off explicitly. In this case the check controls what happens.
|
||||
*/
|
||||
|
||||
#ifdef PNG_MIPS_MSA_API_SUPPORTED
|
||||
switch ((pp->options >> PNG_MIPS_MSA) & 3)
|
||||
{
|
||||
case PNG_OPTION_UNSET:
|
||||
/* Allow the run-time check to execute if it has been enabled -
|
||||
* thus both API and CHECK can be turned on. If it isn't supported
|
||||
* this case will fall through to the 'default' below, which just
|
||||
* returns.
|
||||
*/
|
||||
#ifdef PNG_MIPS_MSA_CHECK_SUPPORTED
|
||||
{
|
||||
static volatile sig_atomic_t no_msa = -1; /* not checked */
|
||||
|
||||
if (no_msa < 0)
|
||||
no_msa = !png_have_msa(pp);
|
||||
|
||||
if (no_msa)
|
||||
return;
|
||||
}
|
||||
#endif /* PNG_MIPS_MSA_CHECK_SUPPORTED */
|
||||
break;
|
||||
|
||||
default: /* OFF or INVALID */
|
||||
return;
|
||||
|
||||
case PNG_OPTION_ON:
|
||||
/* Option turned on */
|
||||
break;
|
||||
}
|
||||
/* IMPORTANT: any new external functions used here must be declared using
|
||||
* PNG_INTERNAL_FUNCTION in ../pngpriv.h. This is required so that the
|
||||
* 'prefix' option to configure works:
|
||||
*
|
||||
* ./configure --with-libpng-prefix=foobar_
|
||||
*
|
||||
* Verify you have got this right by running the above command, doing a build
|
||||
* and examining pngprefix.h; it must contain a #define for every external
|
||||
* function you add. (Notice that this happens automatically for the
|
||||
* initialization function.)
|
||||
*/
|
||||
pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_msa;
|
||||
|
||||
if (bpp == 3)
|
||||
{
|
||||
pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_msa;
|
||||
pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_msa;
|
||||
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth3_msa;
|
||||
}
|
||||
else if (bpp == 4)
|
||||
{
|
||||
pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_msa;
|
||||
pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_msa;
|
||||
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth4_msa;
|
||||
}
|
||||
#else
|
||||
(void)pp;
|
||||
(void)bpp;
|
||||
#endif /* PNG_MIPS_MSA_API_SUPPORTED */
|
||||
}
|
||||
#endif /* PNG_MIPS_MSA_OPT > 0 */
|
||||
#endif /* READ */
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
diff --git a/3rdparty/libpng/mips/mips_init.c b/3rdparty/libpng/mips/mips_init.c
|
||||
index 8dd283deef..6a061cccfa 100644
|
||||
--- a/3rdparty/libpng/mips/mips_init.c
|
||||
+++ b/3rdparty/libpng/mips/mips_init.c
|
||||
@@ -73,7 +73,6 @@ png_init_filter_functions_msa(png_structp pp, unsigned int bpp)
|
||||
* this case will fall through to the 'default' below, which just
|
||||
* returns.
|
||||
*/
|
||||
-#endif /* PNG_MIPS_MSA_API_SUPPORTED */
|
||||
#ifdef PNG_MIPS_MSA_CHECK_SUPPORTED
|
||||
{
|
||||
static volatile sig_atomic_t no_msa = -1; /* not checked */
|
||||
@@ -84,12 +83,9 @@ png_init_filter_functions_msa(png_structp pp, unsigned int bpp)
|
||||
if (no_msa)
|
||||
return;
|
||||
}
|
||||
-#ifdef PNG_MIPS_MSA_API_SUPPORTED
|
||||
- break;
|
||||
-#endif
|
||||
#endif /* PNG_MIPS_MSA_CHECK_SUPPORTED */
|
||||
+ break;
|
||||
|
||||
-#ifdef PNG_MIPS_MSA_API_SUPPORTED
|
||||
default: /* OFF or INVALID */
|
||||
return;
|
||||
|
||||
@@ -97,8 +93,6 @@ png_init_filter_functions_msa(png_structp pp, unsigned int bpp)
|
||||
/* Option turned on */
|
||||
break;
|
||||
}
|
||||
-#endif
|
||||
-
|
||||
/* IMPORTANT: any new external functions used here must be declared using
|
||||
* PNG_INTERNAL_FUNCTION in ../pngpriv.h. This is required so that the
|
||||
* 'prefix' option to configure works:
|
||||
@@ -118,13 +112,16 @@ png_init_filter_functions_msa(png_structp pp, unsigned int bpp)
|
||||
pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_msa;
|
||||
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth3_msa;
|
||||
}
|
||||
-
|
||||
else if (bpp == 4)
|
||||
{
|
||||
pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_msa;
|
||||
pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_msa;
|
||||
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth4_msa;
|
||||
}
|
||||
+#else
|
||||
+ (void)pp;
|
||||
+ (void)bpp;
|
||||
+#endif /* PNG_MIPS_MSA_API_SUPPORTED */
|
||||
}
|
||||
#endif /* PNG_MIPS_MSA_OPT > 0 */
|
||||
#endif /* READ */
|
||||
@@ -0,0 +1,22 @@
|
||||
diff --git a/3rdparty/libwebp/src/dsp/msa_macro.h b/3rdparty/libwebp/src/dsp/msa_macro.h
|
||||
index de026a1d9e..a16c0bb300 100644
|
||||
--- a/3rdparty/libwebp/src/dsp/msa_macro.h
|
||||
+++ b/3rdparty/libwebp/src/dsp/msa_macro.h
|
||||
@@ -73,7 +73,7 @@
|
||||
static inline TYPE FUNC_NAME(const void* const psrc) { \
|
||||
const uint8_t* const psrc_m = (const uint8_t*)psrc; \
|
||||
TYPE val_m; \
|
||||
- asm volatile ( \
|
||||
+ __asm__ volatile ( \
|
||||
"" #INSTR " %[val_m], %[psrc_m] \n\t" \
|
||||
: [val_m] "=r" (val_m) \
|
||||
: [psrc_m] "m" (*psrc_m)); \
|
||||
@@ -86,7 +86,7 @@
|
||||
static inline void FUNC_NAME(TYPE val, void* const pdst) { \
|
||||
uint8_t* const pdst_m = (uint8_t*)pdst; \
|
||||
TYPE val_m = val; \
|
||||
- asm volatile ( \
|
||||
+ __asm__ volatile ( \
|
||||
" " #INSTR " %[val_m], %[pdst_m] \n\t" \
|
||||
: [pdst_m] "=m" (*pdst_m) \
|
||||
: [val_m] "r" (val_m)); \
|
||||
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
+2
-2
@@ -73,7 +73,7 @@
|
||||
static inline TYPE FUNC_NAME(const void* const psrc) { \
|
||||
const uint8_t* const psrc_m = (const uint8_t*)psrc; \
|
||||
TYPE val_m; \
|
||||
asm volatile ( \
|
||||
__asm__ volatile ( \
|
||||
"" #INSTR " %[val_m], %[psrc_m] \n\t" \
|
||||
: [val_m] "=r" (val_m) \
|
||||
: [psrc_m] "m" (*psrc_m)); \
|
||||
@@ -86,7 +86,7 @@
|
||||
static inline void FUNC_NAME(TYPE val, void* const pdst) { \
|
||||
uint8_t* const pdst_m = (uint8_t*)pdst; \
|
||||
TYPE val_m = val; \
|
||||
asm volatile ( \
|
||||
__asm__ volatile ( \
|
||||
" " #INSTR " %[val_m], %[pdst_m] \n\t" \
|
||||
: [pdst_m] "=m" (*pdst_m) \
|
||||
: [val_m] "r" (val_m)); \
|
||||
|
||||
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
|
||||
|
||||
+41
-7
@@ -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)
|
||||
@@ -487,6 +490,7 @@ OCV_OPTION(CV_DISABLE_OPTIMIZATION "Disable explicit optimized code (dispatch
|
||||
OCV_OPTION(CV_TRACE "Enable OpenCV code trace" ON)
|
||||
OCV_OPTION(OPENCV_GENERATE_SETUPVARS "Generate setup_vars* scripts" ON IF (NOT ANDROID AND NOT APPLE_FRAMEWORK) )
|
||||
OCV_OPTION(ENABLE_CONFIG_VERIFICATION "Fail build if actual configuration doesn't match requested (WITH_XXX != HAVE_XXX)" OFF)
|
||||
OCV_OPTION(OPENCV_ENABLE_MEMALIGN "Enable posix_memalign or memalign usage" ON)
|
||||
|
||||
OCV_OPTION(ENABLE_PYLINT "Add target with Pylint checks" (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
|
||||
OCV_OPTION(ENABLE_FLAKE8 "Add target with Python flake8 checker" (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
|
||||
@@ -635,10 +639,15 @@ if(UNIX)
|
||||
set(HAVE_PTHREAD 1)
|
||||
endif()
|
||||
|
||||
CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN)
|
||||
CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H)
|
||||
if(HAVE_MALLOC_H)
|
||||
CHECK_SYMBOL_EXISTS(memalign malloc.h HAVE_MEMALIGN)
|
||||
if(OPENCV_ENABLE_MEMALIGN)
|
||||
CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN)
|
||||
CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H)
|
||||
if(HAVE_MALLOC_H)
|
||||
CHECK_SYMBOL_EXISTS(memalign malloc.h HAVE_MEMALIGN)
|
||||
endif()
|
||||
# TODO:
|
||||
# - _aligned_malloc() on Win32
|
||||
# - std::aligned_alloc() C++17 / C11
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1483,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)
|
||||
@@ -1571,7 +1605,7 @@ if(FLAKE8_FOUND AND FLAKE8_EXECUTABLE)
|
||||
endif()
|
||||
|
||||
# ========================== java ==========================
|
||||
if(BUILD_JAVA OR BUILD_opencv_java)
|
||||
if(BUILD_JAVA)
|
||||
status("")
|
||||
status(" Java:" BUILD_FAT_JAVA_LIB THEN "export all functions" ELSE "")
|
||||
status(" ant:" ANT_EXECUTABLE THEN "${ANT_EXECUTABLE} (ver ${ANT_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,
|
||||
|
||||
@@ -5,13 +5,15 @@
|
||||
# AVX / AVX2 / AVX_512F
|
||||
# FMA3
|
||||
#
|
||||
# AVX512 details: https://en.wikipedia.org/wiki/AVX-512#CPUs_with_AVX-512
|
||||
#
|
||||
# CPU features groups:
|
||||
# AVX512_COMMON (Common instructions AVX-512F/CD for all CPUs that support AVX-512)
|
||||
# AVX512_KNL (Knights Landing with AVX-512F/CD/ER/PF)
|
||||
# AVX512_KNM (Knights Mill with AVX-512F/CD/ER/PF/4FMAPS/4VNNIW/VPOPCNTDQ)
|
||||
# AVX512_SKX (Skylake-X with AVX-512F/CD/BW/DQ/VL)
|
||||
# AVX512_CNL (Cannon Lake with AVX-512F/CD/BW/DQ/VL/IFMA/VBMI)
|
||||
# AVX512_CEL (Cascade Lake with AVX-512F/CD/BW/DQ/VL/IFMA/VBMI/VNNI)
|
||||
# AVX512_CLX (Cascade Lake with AVX-512F/CD/BW/DQ/VL/VNNI)
|
||||
# AVX512_ICL (Ice Lake with AVX-512F/CD/BW/DQ/VL/IFMA/VBMI/VNNI/VBMI2/BITALG/VPOPCNTDQ/VPCLMULQDQ*/GFNI*/VAES*)
|
||||
|
||||
# ppc64le arch:
|
||||
@@ -43,8 +45,9 @@
|
||||
# CPU_{opt}_ENABLED_DEFAULT=ON/OFF - has compiler support without additional flag (CPU_BASELINE_DETECT=ON only)
|
||||
|
||||
set(CPU_ALL_OPTIMIZATIONS "SSE;SSE2;SSE3;SSSE3;SSE4_1;SSE4_2;POPCNT;AVX;FP16;AVX2;FMA3;AVX_512F")
|
||||
list(APPEND CPU_ALL_OPTIMIZATIONS "AVX512_COMMON;AVX512_KNL;AVX512_KNM;AVX512_SKX;AVX512_CNL;AVX512_CEL;AVX512_ICL")
|
||||
list(APPEND CPU_ALL_OPTIMIZATIONS "AVX512_COMMON;AVX512_KNL;AVX512_KNM;AVX512_SKX;AVX512_CNL;AVX512_CLX;AVX512_ICL")
|
||||
list(APPEND CPU_ALL_OPTIMIZATIONS NEON VFPV3 FP16)
|
||||
list(APPEND CPU_ALL_OPTIMIZATIONS MSA)
|
||||
list(APPEND CPU_ALL_OPTIMIZATIONS VSX VSX3)
|
||||
list(REMOVE_DUPLICATES CPU_ALL_OPTIMIZATIONS)
|
||||
|
||||
@@ -162,15 +165,15 @@ elseif(" ${CMAKE_CXX_FLAGS} " MATCHES " -march=native | -xHost | /QxHost ")
|
||||
endif()
|
||||
|
||||
if(X86 OR X86_64)
|
||||
ocv_update(CPU_KNOWN_OPTIMIZATIONS "SSE;SSE2;SSE3;SSSE3;SSE4_1;POPCNT;SSE4_2;FP16;FMA3;AVX;AVX2;AVX_512F;AVX512_COMMON;AVX512_KNL;AVX512_KNM;AVX512_SKX;AVX512_CNL;AVX512_CEL;AVX512_ICL")
|
||||
ocv_update(CPU_KNOWN_OPTIMIZATIONS "SSE;SSE2;SSE3;SSSE3;SSE4_1;POPCNT;SSE4_2;FP16;FMA3;AVX;AVX2;AVX_512F;AVX512_COMMON;AVX512_KNL;AVX512_KNM;AVX512_SKX;AVX512_CNL;AVX512_CLX;AVX512_ICL")
|
||||
|
||||
ocv_update(CPU_AVX512_COMMON_GROUP "AVX_512F;AVX_512CD")
|
||||
ocv_update(CPU_AVX512_KNL_GROUP "AVX512_COMMON;AVX512_KNL_EXTRA")
|
||||
ocv_update(CPU_AVX512_KNM_GROUP "AVX512_KNL;AVX512_KNM_EXTRA;AVX_512VPOPCNTDQ")
|
||||
ocv_update(CPU_AVX512_SKX_GROUP "AVX512_COMMON;AVX_512VL;AVX_512BW;AVX_512DQ")
|
||||
ocv_update(CPU_AVX512_CNL_GROUP "AVX512_SKX;AVX_512IFMA;AVX_512VBMI")
|
||||
ocv_update(CPU_AVX512_CEL_GROUP "AVX512_CNL;AVX_512VNNI")
|
||||
ocv_update(CPU_AVX512_ICL_GROUP "AVX512_CEL;AVX_512VBMI2;AVX_512BITALG;AVX_512VPOPCNTDQ") # ? VPCLMULQDQ, GFNI, VAES
|
||||
ocv_update(CPU_AVX512_CLX_GROUP "AVX512_SKX;AVX_512VNNI")
|
||||
ocv_update(CPU_AVX512_ICL_GROUP "AVX512_SKX;AVX_512IFMA;AVX_512VBMI;AVX_512VNNI;AVX_512VBMI2;AVX_512BITALG;AVX_512VPOPCNTDQ") # ? VPCLMULQDQ, GFNI, VAES
|
||||
|
||||
ocv_update(CPU_SSE_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_sse.cpp")
|
||||
ocv_update(CPU_SSE2_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_sse2.cpp")
|
||||
@@ -188,12 +191,12 @@ if(X86 OR X86_64)
|
||||
ocv_update(CPU_AVX512_KNM_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_avx512knm.cpp")
|
||||
ocv_update(CPU_AVX512_SKX_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_avx512skx.cpp")
|
||||
ocv_update(CPU_AVX512_CNL_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_avx512cnl.cpp")
|
||||
ocv_update(CPU_AVX512_CEL_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_avx512cel.cpp")
|
||||
ocv_update(CPU_AVX512_CLX_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_avx512clx.cpp")
|
||||
ocv_update(CPU_AVX512_ICL_TEST_FILE "${OpenCV_SOURCE_DIR}/cmake/checks/cpu_avx512icl.cpp")
|
||||
|
||||
if(NOT OPENCV_CPU_OPT_IMPLIES_IGNORE)
|
||||
ocv_update(CPU_AVX512_ICL_IMPLIES "AVX512_CEL")
|
||||
ocv_update(CPU_AVX512_CEL_IMPLIES "AVX512_CNL")
|
||||
ocv_update(CPU_AVX512_ICL_IMPLIES "AVX512_SKX")
|
||||
ocv_update(CPU_AVX512_CLX_IMPLIES "AVX512_SKX")
|
||||
ocv_update(CPU_AVX512_CNL_IMPLIES "AVX512_SKX")
|
||||
ocv_update(CPU_AVX512_SKX_IMPLIES "AVX512_COMMON")
|
||||
ocv_update(CPU_AVX512_KNM_IMPLIES "AVX512_KNL")
|
||||
@@ -250,7 +253,7 @@ if(X86 OR X86_64)
|
||||
ocv_intel_compiler_optimization_option(AVX512_KNM "-xKNM" "/Qx:KNM")
|
||||
ocv_intel_compiler_optimization_option(AVX512_SKX "-xSKYLAKE-AVX512" "/Qx:SKYLAKE-AVX512")
|
||||
ocv_intel_compiler_optimization_option(AVX512_CNL "-xCANNONLAKE" "/Qx:CANNONLAKE")
|
||||
ocv_intel_compiler_optimization_option(AVX512_CEL "-xCASCADELAKE" "/Qx:CASCADELAKE")
|
||||
ocv_intel_compiler_optimization_option(AVX512_CLX "-xCASCADELAKE" "/Qx:CASCADELAKE")
|
||||
ocv_intel_compiler_optimization_option(AVX512_ICL "-xICELAKE-CLIENT" "/Qx:ICELAKE-CLIENT")
|
||||
elseif(CV_GCC OR CV_CLANG)
|
||||
ocv_update(CPU_AVX2_FLAGS_ON "-mavx2")
|
||||
@@ -285,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)
|
||||
@@ -339,6 +342,11 @@ elseif(ARM OR AARCH64)
|
||||
ocv_update(CPU_FP16_IMPLIES "NEON")
|
||||
set(CPU_BASELINE "NEON;FP16" CACHE STRING "${HELP_CPU_BASELINE}")
|
||||
endif()
|
||||
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 "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")
|
||||
@@ -706,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,51 +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
|
||||
@@ -128,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)
|
||||
@@ -158,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)
|
||||
@@ -87,10 +101,22 @@ endif()
|
||||
|
||||
if(INF_ENGINE_TARGET)
|
||||
if(NOT INF_ENGINE_RELEASE)
|
||||
message(WARNING "InferenceEngine version have not been set, 2019R2 will be used by default. Set INF_ENGINE_RELEASE variable if you experience build errors.")
|
||||
message(WARNING "InferenceEngine version have not been set, 2019R3 will be used by default. Set INF_ENGINE_RELEASE variable if you experience build errors.")
|
||||
endif()
|
||||
set(INF_ENGINE_RELEASE "2019020000" CACHE STRING "Force IE version, should be in form YYYYAABBCC (e.g. 2018R2.0.2 -> 2018020002)")
|
||||
set(INF_ENGINE_RELEASE "2019030000" CACHE STRING "Force IE version, should be in form YYYYAABBCC (e.g. 2018R2.0.2 -> 2018020002)")
|
||||
set_target_properties(${INF_ENGINE_TARGET} PROPERTIES
|
||||
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()
|
||||
|
||||
@@ -22,6 +22,9 @@ set(OPENCV_DOWNLOAD_PATH "${OpenCV_SOURCE_DIR}/.cache" CACHE PATH "${HELP_OPENCV
|
||||
set(OPENCV_DOWNLOAD_LOG "${OpenCV_BINARY_DIR}/CMakeDownloadLog.txt")
|
||||
set(OPENCV_DOWNLOAD_WITH_CURL "${OpenCV_BINARY_DIR}/download_with_curl.sh")
|
||||
set(OPENCV_DOWNLOAD_WITH_WGET "${OpenCV_BINARY_DIR}/download_with_wget.sh")
|
||||
set(OPENCV_DOWNLOAD_TRIES_LIST 1 CACHE STRING "List of download tries") # a list
|
||||
set(OPENCV_DOWNLOAD_PARAMS INACTIVITY_TIMEOUT 60 TIMEOUT 600 CACHE STRING "Download parameters to be passed to file(DOWNLAOD ...)")
|
||||
mark_as_advanced(OPENCV_DOWNLOAD_TRIES_LIST OPENCV_DOWNLOAD_PARAMS)
|
||||
|
||||
# Init download cache directory and log file and helper scripts
|
||||
if(NOT EXISTS "${OPENCV_DOWNLOAD_PATH}")
|
||||
@@ -154,11 +157,17 @@ function(ocv_download)
|
||||
# Download
|
||||
if(NOT EXISTS "${CACHE_CANDIDATE}")
|
||||
ocv_download_log("#cmake_download \"${CACHE_CANDIDATE}\" \"${DL_URL}\"")
|
||||
file(DOWNLOAD "${DL_URL}" "${CACHE_CANDIDATE}"
|
||||
INACTIVITY_TIMEOUT 60
|
||||
TIMEOUT 600
|
||||
STATUS status
|
||||
LOG __log)
|
||||
foreach(try ${OPENCV_DOWNLOAD_TRIES_LIST})
|
||||
ocv_download_log("#try ${try}")
|
||||
file(DOWNLOAD "${DL_URL}" "${CACHE_CANDIDATE}"
|
||||
STATUS status
|
||||
LOG __log
|
||||
${OPENCV_DOWNLOAD_PARAMS})
|
||||
if(status EQUAL 0)
|
||||
break()
|
||||
endif()
|
||||
message(STATUS "Try ${try} failed")
|
||||
endforeach()
|
||||
if(NOT OPENCV_SKIP_FILE_DOWNLOAD_DUMP) # workaround problem with old CMake versions: "Invalid escape sequence"
|
||||
string(LENGTH "${__log}" __log_length)
|
||||
if(__log_length LESS 65536)
|
||||
@@ -195,8 +204,8 @@ For details please refer to the download log file:
|
||||
${OPENCV_DOWNLOAD_LOG}
|
||||
")
|
||||
# write helper scripts for failed downloads
|
||||
file(APPEND "${OPENCV_DOWNLOAD_WITH_CURL}" "curl --output \"${CACHE_CANDIDATE}\" \"${DL_URL}\"\n")
|
||||
file(APPEND "${OPENCV_DOWNLOAD_WITH_WGET}" "wget -O \"${CACHE_CANDIDATE}\" \"${DL_URL}\"\n")
|
||||
file(APPEND "${OPENCV_DOWNLOAD_WITH_CURL}" "curl --create-dirs --output \"${CACHE_CANDIDATE}\" \"${DL_URL}\"\n")
|
||||
file(APPEND "${OPENCV_DOWNLOAD_WITH_WGET}" "mkdir -p $(dirname ${CACHE_CANDIDATE}) && wget -O \"${CACHE_CANDIDATE}\" \"${DL_URL}\"\n")
|
||||
return()
|
||||
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
|
||||
|
||||
+23
-14
@@ -29,6 +29,16 @@ macro(ippiw_debugmsg MESSAGE)
|
||||
message(STATUS "${MESSAGE}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(ippiw_done)
|
||||
foreach(__file ${IPP_IW_LICENSE_FILES})
|
||||
if(EXISTS "${__file}")
|
||||
ocv_install_3rdparty_licenses(ippiw "${__file}")
|
||||
endif()
|
||||
endforeach()
|
||||
return()
|
||||
endmacro()
|
||||
|
||||
file(TO_CMAKE_PATH "${IPPROOT}" IPPROOT)
|
||||
|
||||
# This function detects Intel IPP Integration Wrappers version by analyzing .h file
|
||||
@@ -81,7 +91,7 @@ macro(ippiw_setup PATH BUILD)
|
||||
if(EXISTS "${FILE}")
|
||||
set(HAVE_IPP_IW_LL 1)
|
||||
endif()
|
||||
return()
|
||||
ippiw_done()
|
||||
else()
|
||||
ippiw_debugmsg("sources\tno")
|
||||
endif()
|
||||
@@ -120,7 +130,7 @@ macro(ippiw_setup PATH BUILD)
|
||||
if(EXISTS "${FILE}")
|
||||
set(HAVE_IPP_IW_LL 1)
|
||||
endif()
|
||||
return()
|
||||
ippiw_done()
|
||||
else()
|
||||
ippiw_debugmsg("binaries\tno")
|
||||
endif()
|
||||
@@ -147,14 +157,12 @@ if(BUILD_IPP_IW)
|
||||
ippiw_setup("${OpenCV_SOURCE_DIR}/3rdparty/ippiw" 1)
|
||||
|
||||
set(IPPIW_ROOT "${IPPROOT}/../iw")
|
||||
ocv_install_3rdparty_licenses(ippiw
|
||||
"${IPPIW_ROOT}/../support.txt"
|
||||
"${IPPIW_ROOT}/../third-party-programs.txt")
|
||||
if(WIN32)
|
||||
ocv_install_3rdparty_licenses(ippiw "${IPPIW_ROOT}/../EULA.rtf")
|
||||
else()
|
||||
ocv_install_3rdparty_licenses(ippiw "${IPPIW_ROOT}/../EULA.txt")
|
||||
endif()
|
||||
set(IPP_IW_LICENSE_FILES ${IPP_IW_LICENSE_FILES_EXTRA}
|
||||
"${IPPIW_ROOT}/../support.txt"
|
||||
"${IPPIW_ROOT}/../third-party-programs.txt"
|
||||
"${IPPIW_ROOT}/../EULA.rtf"
|
||||
"${IPPIW_ROOT}/../EULA.txt"
|
||||
)
|
||||
|
||||
# Package sources
|
||||
get_filename_component(__PATH "${IPPROOT}/../iw/" ABSOLUTE)
|
||||
@@ -167,10 +175,11 @@ if(BUILD_IPP_IW)
|
||||
include("${OpenCV_SOURCE_DIR}/3rdparty/ippicv/ippicv.cmake")
|
||||
download_ippicv(TEMP_ROOT)
|
||||
set(IPPIW_ROOT "${TEMP_ROOT}/iw/")
|
||||
ocv_install_3rdparty_licenses(ippiw
|
||||
"${IPPIW_ROOT}/../EULA.txt"
|
||||
"${IPPIW_ROOT}/../support.txt"
|
||||
"${IPPIW_ROOT}/../third-party-programs.txt")
|
||||
set(IPP_IW_LICENSE_FILES ${IPP_IW_LICENSE_FILES_EXTRA}
|
||||
"${IPPIW_ROOT}/../EULA.txt"
|
||||
"${IPPIW_ROOT}/../support.txt"
|
||||
"${IPPIW_ROOT}/../third-party-programs.txt"
|
||||
)
|
||||
|
||||
ippiw_setup("${IPPIW_ROOT}" 1)
|
||||
endif()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -122,8 +122,10 @@ endif()
|
||||
# Part 3/3: ${BIN_DIR}/win-install/OpenCVConfig.cmake -> For use within binary installers/packages
|
||||
# --------------------------------------------------------------------------------------------
|
||||
if(WIN32)
|
||||
if(CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
||||
ocv_gen_config("${CMAKE_BINARY_DIR}/win-install" "${OPENCV_LIB_INSTALL_PATH}" "OpenCVConfig.root-WIN32.cmake.in")
|
||||
if(CMAKE_HOST_SYSTEM_NAME MATCHES Windows AND NOT OPENCV_SKIP_CMAKE_ROOT_CONFIG)
|
||||
ocv_gen_config("${CMAKE_BINARY_DIR}/win-install"
|
||||
"${OPENCV_INSTALL_BINARIES_PREFIX}${OPENCV_INSTALL_BINARIES_SUFFIX}"
|
||||
"OpenCVConfig.root-WIN32.cmake.in")
|
||||
else()
|
||||
ocv_gen_config("${CMAKE_BINARY_DIR}/win-install" "" "")
|
||||
endif()
|
||||
|
||||
@@ -23,15 +23,15 @@ if(ANDROID)
|
||||
elseif(WIN32 AND CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
||||
|
||||
if(DEFINED OpenCV_RUNTIME AND DEFINED OpenCV_ARCH)
|
||||
set(_prefix "${OpenCV_ARCH}/${OpenCV_RUNTIME}/")
|
||||
ocv_update(OPENCV_INSTALL_BINARIES_PREFIX "${OpenCV_ARCH}/${OpenCV_RUNTIME}/")
|
||||
else()
|
||||
message(STATUS "Can't detect runtime and/or arch")
|
||||
set(_prefix "")
|
||||
ocv_update(OPENCV_INSTALL_BINARIES_PREFIX "")
|
||||
endif()
|
||||
if(OpenCV_STATIC)
|
||||
set(_suffix "staticlib")
|
||||
ocv_update(OPENCV_INSTALL_BINARIES_SUFFIX "staticlib")
|
||||
else()
|
||||
set(_suffix "lib")
|
||||
ocv_update(OPENCV_INSTALL_BINARIES_SUFFIX "lib")
|
||||
endif()
|
||||
if(INSTALL_CREATE_DISTRIB)
|
||||
set(_jni_suffix "/${OpenCV_ARCH}")
|
||||
@@ -39,12 +39,12 @@ elseif(WIN32 AND CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
||||
set(_jni_suffix "")
|
||||
endif()
|
||||
|
||||
ocv_update(OPENCV_BIN_INSTALL_PATH "${_prefix}bin")
|
||||
ocv_update(OPENCV_BIN_INSTALL_PATH "${OPENCV_INSTALL_BINARIES_PREFIX}bin")
|
||||
ocv_update(OPENCV_TEST_INSTALL_PATH "${OPENCV_BIN_INSTALL_PATH}")
|
||||
ocv_update(OPENCV_SAMPLES_BIN_INSTALL_PATH "${_prefix}samples")
|
||||
ocv_update(OPENCV_LIB_INSTALL_PATH "${_prefix}${_suffix}")
|
||||
ocv_update(OPENCV_SAMPLES_BIN_INSTALL_PATH "${OPENCV_INSTALL_BINARIES_PREFIX}samples")
|
||||
ocv_update(OPENCV_LIB_INSTALL_PATH "${OPENCV_INSTALL_BINARIES_PREFIX}${OPENCV_INSTALL_BINARIES_SUFFIX}")
|
||||
ocv_update(OPENCV_LIB_ARCHIVE_INSTALL_PATH "${OPENCV_LIB_INSTALL_PATH}")
|
||||
ocv_update(OPENCV_3P_LIB_INSTALL_PATH "${_prefix}staticlib")
|
||||
ocv_update(OPENCV_3P_LIB_INSTALL_PATH "${OPENCV_INSTALL_BINARIES_PREFIX}staticlib")
|
||||
ocv_update(OPENCV_CONFIG_INSTALL_PATH ".")
|
||||
ocv_update(OPENCV_INCLUDE_INSTALL_PATH "include")
|
||||
ocv_update(OPENCV_OTHER_INSTALL_PATH "etc")
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
static int test()
|
||||
{
|
||||
std::atomic<int> x;
|
||||
std::atomic<long long> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,5 +6,6 @@ void test()
|
||||
{
|
||||
int data[8] = {0,0,0,0, 0,0,0,0};
|
||||
__m256i a = _mm256_loadu_si256((const __m256i *)data);
|
||||
__m256i b = _mm256_bslli_epi128(a, 1); // available in GCC 4.9.3+
|
||||
}
|
||||
int main() { return 0; }
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
void test()
|
||||
{
|
||||
__m512i a, b, c;
|
||||
a = _mm512_dpwssd_epi32(a, b, c);
|
||||
a = _mm512_dpwssd_epi32(a, b, c); // VNNI
|
||||
}
|
||||
#else
|
||||
#error "AVX512-CEL is not supported"
|
||||
#error "AVX512-CLX is not supported"
|
||||
#endif
|
||||
int main() { return 0; }
|
||||
int main() { return 0; }
|
||||
@@ -3,9 +3,10 @@
|
||||
void test()
|
||||
{
|
||||
__m512i a, b, c;
|
||||
a = _mm512_popcnt_epi8(a);
|
||||
a = _mm512_shrdv_epi64(a, b, c);
|
||||
a = _mm512_popcnt_epi64(a);
|
||||
a = _mm512_popcnt_epi8(a); // BITALG
|
||||
a = _mm512_shrdv_epi64(a, b, c); // VBMI2
|
||||
a = _mm512_popcnt_epi64(a); // VPOPCNTDQ
|
||||
a = _mm512_dpwssd_epi32(a, b, c); // VNNI
|
||||
}
|
||||
#else
|
||||
#error "AVX512-ICL is not supported"
|
||||
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(__mips_msa)
|
||||
# include <msa.h>
|
||||
# define CV_MSA 1
|
||||
#endif
|
||||
|
||||
#if defined CV_MSA
|
||||
int test()
|
||||
{
|
||||
const float src[] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
v4f32 val = (v4f32)__msa_ld_w((const float*)(src), 0);
|
||||
return __msa_copy_s_w(__builtin_msa_ftint_s_w (val), 0);
|
||||
}
|
||||
#else
|
||||
#error "MSA is not supported"
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("%d\n", test());
|
||||
return 0;
|
||||
}
|
||||
@@ -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,144 @@ 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
|
||||
|
||||
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`).
|
||||
|
||||
|
||||
-# [optional] To build `opencv.js` with threads optimization, append `--threads` option.
|
||||
|
||||
For example:
|
||||
@code{.sh}
|
||||
cd bin
|
||||
npm install
|
||||
node tests.js
|
||||
@code{.bash}
|
||||
python ./platforms/js/build_js.py build_js --build_wasm --threads
|
||||
@endcode
|
||||
|
||||
The default threads number is the logic core number of your device. You can use `cv.parallel_pthreads_set_threads_num(number)` to set threads number by yourself and use `cv.parallel_pthreads_get_threads_num()` to get the current threads number.
|
||||
|
||||
@note
|
||||
You should build wasm version of `opencv.js` if you want to enable this optimization. And the threads optimization only works in browser, not in node.js. You need to enable the `WebAssembly threads support` feature first with your browser. For example, if you use Chrome, please enable this flag in chrome://flags.
|
||||
|
||||
-# [optional] To build `opencv.js` with wasm simd optimization, append `--simd` option.
|
||||
|
||||
For example:
|
||||
@code{.bash}
|
||||
python ./platforms/js/build_js.py build_js --build_wasm --simd
|
||||
@endcode
|
||||
|
||||
The simd optimization is experimental as wasm simd is still in development.
|
||||
|
||||
@note
|
||||
Now only emscripten LLVM upstream backend supports wasm simd, refering to https://emscripten.org/docs/porting/simd.html. So you need to setup upstream backend environment with the following command first:
|
||||
@code{.bash}
|
||||
./emsdk update
|
||||
./emsdk install latest-upstream
|
||||
./emsdk activate latest-upstream
|
||||
source ./emsdk_env.sh
|
||||
@endcode
|
||||
|
||||
@note
|
||||
It requires `node` installed in your development environment.
|
||||
You should build wasm version of `opencv.js` if you want to enable this optimization. For browser, you need to enable the `WebAssembly SIMD support` feature first. For example, if you use Chrome, please enable this flag in chrome://flags. For Node.js, you need to run script with flag `--experimental-wasm-simd`.
|
||||
|
||||
@note
|
||||
The simd version of `opencv.js` built by latest LLVM upstream may not work with the stable browser or old version of Node.js. Please use the latest version of unstable browser or Node.js to get new features, like `Chrome Dev`.
|
||||
|
||||
-# [optional] To build wasm intrinsics tests, append `--build_wasm_intrin_test` option.
|
||||
|
||||
For example:
|
||||
@code{.bash}
|
||||
python ./platforms/js/build_js.py build_js --build_wasm --simd --build_wasm_intrin_test
|
||||
@endcode
|
||||
|
||||
For wasm intrinsics tests, you can use the following function to test all the cases:
|
||||
@code{.js}
|
||||
cv.test_hal_intrin_all()
|
||||
@endcode
|
||||
|
||||
And the failed cases will be logged in the JavaScript debug console.
|
||||
|
||||
If you only want to test single data type of wasm intrinsics, you can use the following functions:
|
||||
@code{.js}
|
||||
cv.test_hal_intrin_uint8()
|
||||
cv.test_hal_intrin_int8()
|
||||
cv.test_hal_intrin_uint16()
|
||||
cv.test_hal_intrin_int16()
|
||||
cv.test_hal_intrin_uint32()
|
||||
cv.test_hal_intrin_int32()
|
||||
cv.test_hal_intrin_uint64()
|
||||
cv.test_hal_intrin_int64()
|
||||
cv.test_hal_intrin_float32()
|
||||
cv.test_hal_intrin_float64()
|
||||
@endcode
|
||||
|
||||
-# [optional] To build performance tests, append `--build_perf` option.
|
||||
|
||||
For example:
|
||||
@code{.bash}
|
||||
python ./platforms/js/build_js.py build_js --build_perf
|
||||
@endcode
|
||||
|
||||
To run performance tests, launch a local web server in \<build_dir\>/bin folder. For example, node http-server which serves on `localhost:8080`.
|
||||
|
||||
There are some kernels now in the performance test like `cvtColor`, `resize` and `threshold`. For example, if you want to test `threshold`, please navigate the web browser to `http://localhost:8080/perf/perf_imgproc/perf_threshold.html`. You need to input the test parameter like `(1920x1080, CV_8UC1, THRESH_BINARY)`, and then click the `Run` button to run the case. And if you don't input the parameter, it will run all the cases of this kernel.
|
||||
|
||||
You can also run tests using Node.js.
|
||||
|
||||
For example, run `threshold` with parameter `(1920x1080, CV_8UC1, THRESH_BINARY)`:
|
||||
@code{.sh}
|
||||
cd bin/perf
|
||||
npm install
|
||||
node perf_threshold.js --test_param_filter="(1920x1080, CV_8UC1, THRESH_BINARY)"
|
||||
@endcode
|
||||
|
||||
Building OpenCV.js with Docker
|
||||
---------------------------------------
|
||||
@@ -117,14 +240,41 @@ So, make sure [docker](https://www.docker.com/) is installed in your system and
|
||||
@code{.bash}
|
||||
git clone https://github.com/opencv/opencv.git
|
||||
cd opencv
|
||||
docker run --rm --workdir /code -v "$PWD":/code "trzeci/emscripten:latest" python ./platforms/js/build_js.py build_js
|
||||
docker run --rm --workdir /code -v "$PWD":/code "trzeci/emscripten:latest" python ./platforms/js/build_js.py build
|
||||
@endcode
|
||||
|
||||
In Windows use the following PowerShell command:
|
||||
|
||||
@code{.bash}
|
||||
docker run --rm --workdir /code -v "$(get-location):/code" "trzeci/emscripten:latest" python ./platforms/js/build_js.py build_js
|
||||
docker run --rm --workdir /code -v "$(get-location):/code" "trzeci/emscripten:latest" python ./platforms/js/build_js.py build
|
||||
@endcode
|
||||
|
||||
@note
|
||||
The example uses latest version of [trzeci/emscripten](https://hub.docker.com/r/trzeci/emscripten) docker container. At this time, the latest version works fine and is `trzeci/emscripten:sdk-tag-1.38.32-64bit`
|
||||
@warning
|
||||
The example uses latest version of emscripten. If the build fails you should try a version that is known to work fine which is `1.38.32` using the following command:
|
||||
|
||||
@code{.bash}
|
||||
docker run --rm --workdir /code -v "$PWD":/code "trzeci/emscripten:sdk-tag-1.38.32-64bit" python ./platforms/js/build_js.py build
|
||||
@endcode
|
||||
|
||||
### Building the documentation with Docker
|
||||
|
||||
To build the documentation `doxygen` needs to be installed. Create a file named `Dockerfile` with the following content:
|
||||
|
||||
```
|
||||
FROM trzeci/emscripten:sdk-tag-1.38.32-64bit
|
||||
|
||||
RUN apt-get update -y
|
||||
RUN apt-get install -y doxygen
|
||||
```
|
||||
|
||||
Then we build the docker image and name it `opencv-js-doc` with the following command (that needs to be run only once):
|
||||
|
||||
@code{.bash}
|
||||
docker build . -t opencv-js-doc
|
||||
@endcode
|
||||
|
||||
Now run the build command again, this time using the new image and passing `--build_doc`:
|
||||
|
||||
@code{.bash}
|
||||
docker run --rm --workdir /code -v "$PWD":/code "opencv-js-doc" python ./platforms/js/build_js.py build --build_doc
|
||||
@endcode
|
||||
|
||||
@@ -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,7 +4,7 @@ Getting Started with Images {#tutorial_py_image_display}
|
||||
Goals
|
||||
-----
|
||||
|
||||
- Here, you will learn how to read an image, how to display it and how to save it back
|
||||
- Here, you will learn how to read an image, how to display it, and how to save it back
|
||||
- You will learn these functions : **cv.imread()**, **cv.imshow()** , **cv.imwrite()**
|
||||
- Optionally, you will learn how to display images with Matplotlib
|
||||
|
||||
@@ -30,7 +30,7 @@ See the code below:
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
# Load an color image in grayscale
|
||||
# Load a color image in grayscale
|
||||
img = cv.imread('messi5.jpg',0)
|
||||
@endcode
|
||||
|
||||
@@ -43,7 +43,7 @@ Even if the image path is wrong, it won't throw any error, but `print img` will
|
||||
Use the function **cv.imshow()** to display an image in a window. The window automatically fits to
|
||||
the image size.
|
||||
|
||||
First argument is a window name which is a string. second argument is our image. You can create as
|
||||
First argument is a window name which is a string. Second argument is our image. You can create as
|
||||
many windows as you wish, but with different window names.
|
||||
@code{.py}
|
||||
cv.imshow('image',img)
|
||||
@@ -66,11 +66,11 @@ MUST use it to actually display the image.
|
||||
specific window, use the function **cv.destroyWindow()** where you pass the exact window name as
|
||||
the argument.
|
||||
|
||||
@note There is a special case where you can already create a window and load image to it later. In
|
||||
that case, you can specify whether window is resizable or not. It is done with the function
|
||||
**cv.namedWindow()**. By default, the flag is cv.WINDOW_AUTOSIZE. But if you specify flag to be
|
||||
cv.WINDOW_NORMAL, you can resize window. It will be helpful when image is too large in dimension
|
||||
and adding track bar to windows.
|
||||
@note There is a special case where you can create an empty window and load an image to it later. In
|
||||
that case, you can specify whether the window is resizable or not. It is done with the function
|
||||
**cv.namedWindow()**. By default, the flag is cv.WINDOW_AUTOSIZE. But if you specify the flag to be
|
||||
cv.WINDOW_NORMAL, you can resize window. It will be helpful when an image is too large in dimension
|
||||
and when adding track bars to windows.
|
||||
|
||||
See the code below:
|
||||
@code{.py}
|
||||
@@ -91,8 +91,8 @@ This will save the image in PNG format in the working directory.
|
||||
|
||||
### Sum it up
|
||||
|
||||
Below program loads an image in grayscale, displays it, save the image if you press 's' and exit, or
|
||||
simply exit without saving if you press ESC key.
|
||||
Below program loads an image in grayscale, displays it, saves the image if you press 's' and exit, or
|
||||
simply exits without saving if you press ESC key.
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
@@ -117,7 +117,7 @@ Using Matplotlib
|
||||
|
||||
Matplotlib is a plotting library for Python which gives you wide variety of plotting methods. You
|
||||
will see them in coming articles. Here, you will learn how to display image with Matplotlib. You can
|
||||
zoom images, save it etc using Matplotlib.
|
||||
zoom images, save them, etc, using Matplotlib.
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
@@ -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
|
||||
--------------------
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user