mirror of
https://github.com/opencv/opencv.git
synced 2026-07-25 21:33:04 +04:00
Compare commits
501 Commits
4.5.2-openvino
...
4.5.3
| Author | SHA1 | Date | |
|---|---|---|---|
| ad6e82942b | |||
| d60bb57d4b | |||
| f9d62fba7a | |||
| 85dde8a800 | |||
| 9d039c206b | |||
| cbff19ff1a | |||
| 4c3f9b2ef4 | |||
| 167bac23aa | |||
| 5d0cfa2527 | |||
| 0e523618a1 | |||
| 821fae0d94 | |||
| 3b26105f68 | |||
| 0f2f966a91 | |||
| d7d491d445 | |||
| 41effbe2da | |||
| 9b0d6862c4 | |||
| 890fcdf842 | |||
| 18dbac203f | |||
| 8d1f254dcc | |||
| e5841d3126 | |||
| 90df3af6cf | |||
| 11cc36d770 | |||
| 05f1939b02 | |||
| 050ea9762f | |||
| 0f24d4d2a1 | |||
| fc799191f4 | |||
| 8fad85edda | |||
| d70053aba5 | |||
| b699fe7a9d | |||
| 94c67faaea | |||
| b2ed5c3070 | |||
| 9fe49497bb | |||
| 5b8c10f2f8 | |||
| 24983f62e2 | |||
| f2057ce1ab | |||
| 6797fd65a5 | |||
| bf489feef1 | |||
| 947e06a860 | |||
| 6a3d925a47 | |||
| 04d5ba266f | |||
| 90be83ae99 | |||
| 5e80bd3cc9 | |||
| fb7ef76e74 | |||
| db4b1e613c | |||
| ee39081b11 | |||
| 7d842f5bcf | |||
| 4eac198270 | |||
| faac32418c | |||
| 42810621df | |||
| 61a5378aeb | |||
| 42d644ef91 | |||
| c95a56450d | |||
| dc5199feea | |||
| f88fdf6a1b | |||
| b68057d927 | |||
| e9a860d9cb | |||
| 8be86cbdfd | |||
| 5091e64a42 | |||
| 828304d587 | |||
| 9d584475f6 | |||
| bb60cb0bf9 | |||
| 25f908b320 | |||
| 9b7dca2fa1 | |||
| 55e1dfb778 | |||
| 735a79ae83 | |||
| ef2b400c61 | |||
| c2263db7bc | |||
| 53eca2ff5b | |||
| 7bbbda71df | |||
| 9557b9f70f | |||
| 464441d8c3 | |||
| f30f1afd47 | |||
| b3db37b99d | |||
| 7a276f39fb | |||
| 415668ecf0 | |||
| 651967b95c | |||
| 8e0baf257c | |||
| c8268e65fd | |||
| 3cf4375387 | |||
| 438e2dc228 | |||
| c1adbe3189 | |||
| 7ee1816612 | |||
| b4084491e5 | |||
| cb97421edf | |||
| e461031d40 | |||
| c82e4596e4 | |||
| 8f4f834ce6 | |||
| 15ba3e123f | |||
| 2db243b8ed | |||
| b57b64b7a3 | |||
| 8e386ac71f | |||
| bc1af6227a | |||
| 2b84c97a78 | |||
| 3ddf84534b | |||
| 4c2dff88de | |||
| bd26104088 | |||
| 80238880e6 | |||
| f4abafb093 | |||
| 3e538355e2 | |||
| 5f80f43ff5 | |||
| 76e9da3fe9 | |||
| cafa04f842 | |||
| fef84f69ec | |||
| ba98cd97e5 | |||
| 81b897c291 | |||
| 1c4d70896a | |||
| 039bcd932a | |||
| eaa9228a4f | |||
| a8757df963 | |||
| b221143c0f | |||
| 2c796de92b | |||
| 6f2a64a511 | |||
| 995841624c | |||
| f5f675ef6c | |||
| bdc8e9118b | |||
| d9ed9a9a83 | |||
| b57faa41c2 | |||
| 1b5fe91624 | |||
| 1a305cadb3 | |||
| bbcd06f42f | |||
| 34183237ce | |||
| 286ec92967 | |||
| 43940f7ffc | |||
| b05631432b | |||
| dc92886ab6 | |||
| 993416d9cf | |||
| f4a79b0554 | |||
| 411fd2b761 | |||
| 327109f327 | |||
| f1f9121bc7 | |||
| 3b42e19505 | |||
| 709156ee65 | |||
| 472030907b | |||
| 61e30c15a9 | |||
| d332f33346 | |||
| 636db09d73 | |||
| 64c018507b | |||
| 3e513ee6ab | |||
| c34445a496 | |||
| c2ce3d927a | |||
| ff60abb575 | |||
| 7d91dfe339 | |||
| 15af65d4cf | |||
| 0e8431d17b | |||
| 81afeda537 | |||
| e10de25e86 | |||
| 826fdaf06c | |||
| a4d0a1483a | |||
| 746bd47ce5 | |||
| dcb4cabb26 | |||
| 59b4baee0c | |||
| 2610724ee0 | |||
| 61359a5bd0 | |||
| bb3bbd192b | |||
| de781b306f | |||
| 1212aef03b | |||
| 814550d2a6 | |||
| 478663b08c | |||
| fb9a00c36d | |||
| fb68fe8930 | |||
| 73ee01a7f4 | |||
| eb9b5fa9a5 | |||
| 8bd5405228 | |||
| cb51a155b2 | |||
| d3be58b6d7 | |||
| 8ecfbdb4ff | |||
| 63256a00ff | |||
| 450dc92452 | |||
| 9c16408e91 | |||
| d42a2b2d16 | |||
| 3d2f4fa164 | |||
| 3d394943e6 | |||
| cf96a9fd27 | |||
| 76e81dfbb0 | |||
| 684ba6fe14 | |||
| 830cb5cad7 | |||
| 3e25f32c9b | |||
| 81567a9d3e | |||
| 2b06208bbd | |||
| 5f637e5a02 | |||
| cc712a165d | |||
| 4a2adba8f4 | |||
| 84f78059d3 | |||
| b67c0e5f4a | |||
| 1e1ddd3279 | |||
| 70f69cb265 | |||
| ae4cc404c1 | |||
| 32df5faa25 | |||
| ac8e7d57dc | |||
| da4a531717 | |||
| fea12f7806 | |||
| 7499a15c92 | |||
| 115e471515 | |||
| c4df8989e9 | |||
| 0f11b1fc0d | |||
| 5f4e55bc68 | |||
| c621384707 | |||
| c0162a64d1 | |||
| 527d86a93d | |||
| 7d66f1e391 | |||
| 6265155ce4 | |||
| 70d1ff7155 | |||
| 4753206783 | |||
| 6376a3aef2 | |||
| 1ae16beb06 | |||
| e53a4ce64d | |||
| 72655a9eea | |||
| 125f890dc3 | |||
| 101d50703c | |||
| 901ed5545f | |||
| a604d44d06 | |||
| bb92eb5a93 | |||
| 699b4b9fc5 | |||
| 1fb3133ec5 | |||
| fea45c6911 | |||
| 1d7d18afba | |||
| aadbebf9d8 | |||
| 7e12af2448 | |||
| b335fe67b0 | |||
| 776d92e797 | |||
| dde029f105 | |||
| 7ffc02283b | |||
| 7a31a6edee | |||
| df05bc65c5 | |||
| 3a49ff9e72 | |||
| 302c2354a3 | |||
| 158b13e0ba | |||
| 71e2a17fdb | |||
| b1dc7ed873 | |||
| 1bced43e96 | |||
| 7de627c504 | |||
| 6a4bfc0863 | |||
| 170bf6d7af | |||
| 8550f7e04d | |||
| 9f3e83baf6 | |||
| 17ab61a40d | |||
| 1b844f8413 | |||
| baa22fa808 | |||
| f78cebfc98 | |||
| d2a9ca13f1 | |||
| 71bae7c23f | |||
| 1dacea3a20 | |||
| 083a7c8f0a | |||
| d4f104f17f | |||
| fd44ba296d | |||
| 4ed91ce7ed | |||
| b04d6a2d9b | |||
| 15e2f991dd | |||
| a08eac452e | |||
| 0c171c0749 | |||
| 7021ea6748 | |||
| dbd65a3b01 | |||
| 55aa1d4852 | |||
| 971dacaf41 | |||
| 159534313e | |||
| 2f68c43e39 | |||
| e2483aa072 | |||
| 6c53af8e41 | |||
| c4ca9a7bae | |||
| c69f37343c | |||
| aec62a7fc5 | |||
| bf26050f7e | |||
| 402bce1a31 | |||
| e68657cdb2 | |||
| e00cfe067d | |||
| 8868350888 | |||
| fcaeeac931 | |||
| a53582d706 | |||
| e655083e3c | |||
| 1b64851fa8 | |||
| 40a7c70969 | |||
| 2e143b8799 | |||
| 5105a937d1 | |||
| 3930c9a492 | |||
| 29fb4f98b1 | |||
| f0839d2703 | |||
| 405e820fe1 | |||
| 3386efddba | |||
| c41650db20 | |||
| a0ff55db7d | |||
| 896bffb543 | |||
| 0df6159149 | |||
| cfb77091ca | |||
| 6598e9d506 | |||
| 8c2cf89845 | |||
| aeb8dfc52d | |||
| 0649a2fbdb | |||
| ec32061f5f | |||
| f2da1a0a7a | |||
| fda1e6f148 | |||
| 2a48730166 | |||
| 0bdbc745c4 | |||
| 6f70b0524a | |||
| b9b19185bc | |||
| 63ba9970bd | |||
| 1f726e81f9 | |||
| a9a6801c6d | |||
| 222af8e7e4 | |||
| df71853075 | |||
| bfb10d74eb | |||
| ec8b7c933a | |||
| 68d15fc62e | |||
| f479935cda | |||
| 76860933f0 | |||
| 19a936fc03 | |||
| be17fce657 | |||
| 9a1d7736f8 | |||
| 9f295b2c91 | |||
| 6e8daaec0f | |||
| 3a8154051f | |||
| f3f46096d6 | |||
| ace37df941 | |||
| de7377485b | |||
| e23578acd9 | |||
| 770445ae2a | |||
| b9b65e9392 | |||
| ac9182f20d | |||
| 125b9f6057 | |||
| 69357b1e88 | |||
| e9e9e3898a | |||
| 9ef20ad20e | |||
| 2cf1a13755 | |||
| 6465e393b6 | |||
| 6e6c0f31f7 | |||
| 1263949e70 | |||
| 12d80b9e64 | |||
| d0e3e638c3 | |||
| ad333e0d22 | |||
| 34a8a45a6a | |||
| 6a72bf5085 | |||
| 1e51f87298 | |||
| 8095f601d1 | |||
| 0ff57e3292 | |||
| 5db484b6c2 | |||
| b40d24ad75 | |||
| 6865787a75 | |||
| 7f664850f5 | |||
| 2907fb88f5 | |||
| f839fa4070 | |||
| 32d51313d0 | |||
| 69341edfe6 | |||
| 81f0b0e0dc | |||
| d7cb2ea210 | |||
| 28f919d9d2 | |||
| 4ae2c11520 | |||
| 3e1673e8b2 | |||
| 1b3e0b27af | |||
| e4b0251e9d | |||
| b26f5b9468 | |||
| 5340dc6686 | |||
| 174753921d | |||
| aa32e3deb1 | |||
| 2b86de217a | |||
| 1615afd7f4 | |||
| 908957317f | |||
| 6fa2bdd7f2 | |||
| f82303d614 | |||
| 6773fa03e2 | |||
| 47fe017a6c | |||
| 7baae20c20 | |||
| 921c4551d9 | |||
| c20a424e3a | |||
| 2e005f5dc2 | |||
| 9f13fdb840 | |||
| e6f52b0996 | |||
| d651ff8d6b | |||
| e11408f6ad | |||
| 8069a6b4f8 | |||
| b697b3162f | |||
| 53a16b1186 | |||
| a2a92999be | |||
| 40c0830b63 | |||
| 6f1eefec69 | |||
| 61a4100d0c | |||
| bb6e15f2c0 | |||
| 0dcb99cf23 | |||
| 69fc0acd1a | |||
| 3f14cb073b | |||
| cc6d48959e | |||
| 5ffe32439d | |||
| 76a9c0ccb0 | |||
| aab62aa6dd | |||
| c89084e6b7 | |||
| 64072e44cc | |||
| e7007668a6 | |||
| 105b57c8d9 | |||
| 79d4a38d87 | |||
| e08de1101d | |||
| b5339cc01b | |||
| ac9f3a1242 | |||
| 53652a6194 | |||
| 8d232a63ad | |||
| 35eaacd1db | |||
| bf03f5fa3a | |||
| 6e8022a3af | |||
| d27eb79fa6 | |||
| 3e48a91d97 | |||
| ad2f5ccc66 | |||
| 77bfd9434b | |||
| 144443d011 | |||
| 6ba99068c9 | |||
| 86d0a86141 | |||
| b7f6584dab | |||
| 3290a5f370 | |||
| bf9f67e93f | |||
| 26ea4760ad | |||
| 0753408e10 | |||
| f59917bea1 | |||
| b62d015285 | |||
| a394c8b10b | |||
| 24002a5dfe | |||
| 7c4b873ba3 | |||
| e56e4876e7 | |||
| 7949983c41 | |||
| 56bdd7db5c | |||
| 3df6bc58e9 | |||
| b0d66e06f4 | |||
| e75f1b071b | |||
| 7a2b3ed471 | |||
| 551d4a8ec1 | |||
| 29a289dfa1 | |||
| a00d6b8377 | |||
| ca8c3dd9b5 | |||
| c434ca74a2 | |||
| bdd2b57e5d | |||
| a97f6f8058 | |||
| c0dd82fb53 | |||
| 94f00cf096 | |||
| 1211a8b9cd | |||
| 50a264d832 | |||
| 3f52d0e46c | |||
| 716bdd5ee5 | |||
| bad08d26da | |||
| a41394c885 | |||
| f680505086 | |||
| ae60bbc7e4 | |||
| dc31e20925 | |||
| 7664e6d090 | |||
| af63fffb63 | |||
| 0a6adedaf1 | |||
| b19f860384 | |||
| 960f501cc1 | |||
| 7a8e171691 | |||
| 7ca9740da5 | |||
| 68fae94cbb | |||
| 6da5c7c1d0 | |||
| 87e607a19b | |||
| cbe236652b | |||
| d4d805cb3e | |||
| 8d29a902e4 | |||
| 4c1d5840bb | |||
| f136adcad5 | |||
| 95ab9468c1 | |||
| f8181fbef8 | |||
| c5c2b6f9bf | |||
| b995de4ff3 | |||
| 825dadfbdd | |||
| 0f4b27c300 | |||
| 63048812c7 | |||
| fbb38cc245 | |||
| c1a57a10a4 | |||
| e4692ac079 | |||
| 12fa8d8444 | |||
| 47337e2196 | |||
| ddd2447192 | |||
| 1d6a1e5f9c | |||
| 04d907fb97 | |||
| 84fcc4ab9b | |||
| 65b51e1538 | |||
| e2610df073 | |||
| 6c9be1bc1d | |||
| 4c48f1eed2 | |||
| 31f66766b7 | |||
| 601690695e | |||
| 4287961aed | |||
| 85009800b3 | |||
| d643a90efa | |||
| 04a9ff88d8 | |||
| dc24663e8d | |||
| d2cc63e779 | |||
| d0fe6ad109 | |||
| 358878caf7 | |||
| b450dd7a87 | |||
| 640f188ca2 | |||
| a1e2c4f338 | |||
| 625d4fc884 | |||
| f821530eb0 | |||
| 7894cd3c73 | |||
| 125cc79c17 | |||
| 2e429268ff | |||
| 2a808aeec0 | |||
| 94533e12eb | |||
| a0008de281 | |||
| a42d4da003 | |||
| e2ca50f1cb | |||
| 0689c70dba | |||
| 75ad74c893 | |||
| cbfd38bd41 | |||
| cc22a73d0f | |||
| 1b0f781b7c | |||
| 8c74d7e4fa |
Vendored
+6
-6
@@ -1,9 +1,9 @@
|
||||
# Binaries branch name: ffmpeg/master_20210303
|
||||
# Binaries were created for OpenCV: 7ac6abe02a33bef445a5b77214ad31964e2c5cc1
|
||||
ocv_update(FFMPEG_BINARIES_COMMIT "629590c3ba09fb0c8eaa9ab858ff13d3a84ca1aa")
|
||||
ocv_update(FFMPEG_FILE_HASH_BIN32 "638065d5a0dab8a828879942375dcac4")
|
||||
ocv_update(FFMPEG_FILE_HASH_BIN64 "7f10ae2e6a080ba3714f7a38ee03ae15")
|
||||
ocv_update(FFMPEG_FILE_HASH_CMAKE "f8e65dbe4a3b4eedc0d2997e07c3f3fd")
|
||||
# Binaries branch name: ffmpeg/master_20210608
|
||||
# Binaries were created for OpenCV: eaa9228a4fdfb9c2465aea65a50ce2d16b55dce0
|
||||
ocv_update(FFMPEG_BINARIES_COMMIT "213fcd5d4897319a83207406036c4a5957fba010")
|
||||
ocv_update(FFMPEG_FILE_HASH_BIN32 "bab661341c30862fa88627130219c0a5")
|
||||
ocv_update(FFMPEG_FILE_HASH_BIN64 "ac99f9767a83103c31709628af685924")
|
||||
ocv_update(FFMPEG_FILE_HASH_CMAKE "8862c87496e2e8c375965e1277dee1c7")
|
||||
|
||||
function(download_win_ffmpeg script_var)
|
||||
set(${script_var} "" PARENT_SCOPE)
|
||||
|
||||
+3
-4
@@ -3,10 +3,10 @@ project(${JPEG_LIBRARY} C)
|
||||
ocv_warnings_disable(CMAKE_C_FLAGS -Wunused-parameter -Wsign-compare -Wshorten-64-to-32 -Wimplicit-fallthrough)
|
||||
|
||||
set(VERSION_MAJOR 2)
|
||||
set(VERSION_MINOR 0)
|
||||
set(VERSION_REVISION 6)
|
||||
set(VERSION_MINOR 1)
|
||||
set(VERSION_REVISION 0)
|
||||
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION})
|
||||
set(LIBJPEG_TURBO_VERSION_NUMBER 2000006)
|
||||
set(LIBJPEG_TURBO_VERSION_NUMBER 2001000)
|
||||
|
||||
string(TIMESTAMP BUILD "opencv-${OPENCV_VERSION}-libjpeg-turbo")
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
@@ -46,7 +46,6 @@ if(UNIX)
|
||||
ocv_update(HAVE_UNSIGNED_SHORT 1)
|
||||
# undef INCOMPLETE_TYPES_BROKEN
|
||||
ocv_update(RIGHT_SHIFT_IS_UNSIGNED 0)
|
||||
ocv_update(__CHAR_UNSIGNED__ 0)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -91,7 +91,7 @@ best of our understanding.
|
||||
The Modified (3-clause) BSD License
|
||||
===================================
|
||||
|
||||
Copyright (C)2009-2020 D. R. Commander. All Rights Reserved.
|
||||
Copyright (C)2009-2021 D. R. Commander. All Rights Reserved.<br>
|
||||
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
Vendored
+1
-14
@@ -128,7 +128,7 @@ with respect to this software, its quality, accuracy, merchantability, or
|
||||
fitness for a particular purpose. This software is provided "AS IS", and you,
|
||||
its user, assume the entire risk as to its quality and accuracy.
|
||||
|
||||
This software is copyright (C) 1991-2016, Thomas G. Lane, Guido Vollbeding.
|
||||
This software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
|
||||
All Rights Reserved except as specified below.
|
||||
|
||||
Permission is hereby granted to use, copy, modify, and distribute this
|
||||
@@ -159,19 +159,6 @@ commercial products, provided that all warranty or liability claims are
|
||||
assumed by the product vendor.
|
||||
|
||||
|
||||
The IJG distribution formerly included code to read and write GIF files.
|
||||
To avoid entanglement with the Unisys LZW patent (now expired), GIF reading
|
||||
support has been removed altogether, and the GIF writer has been simplified
|
||||
to produce "uncompressed GIFs". This technique does not use the LZW
|
||||
algorithm; the resulting GIF files are larger than usual, but are readable
|
||||
by all standard GIF decoders.
|
||||
|
||||
We are required to state that
|
||||
"The Graphics Interchange Format(c) is the Copyright property of
|
||||
CompuServe Incorporated. GIF(sm) is a Service Mark property of
|
||||
CompuServe Incorporated."
|
||||
|
||||
|
||||
REFERENCES
|
||||
==========
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ Background
|
||||
|
||||
libjpeg-turbo is a JPEG image codec that uses SIMD instructions to accelerate
|
||||
baseline JPEG compression and decompression on x86, x86-64, Arm, PowerPC, and
|
||||
MIPS systems, as well as progressive JPEG compression on x86 and x86-64
|
||||
MIPS systems, as well as progressive JPEG compression on x86, x86-64, and Arm
|
||||
systems. On such systems, libjpeg-turbo is generally 2-6x as fast as libjpeg,
|
||||
all else being equal. On other types of systems, libjpeg-turbo can still
|
||||
outperform libjpeg by a significant amount, by virtue of its highly-optimized
|
||||
|
||||
Vendored
-5
@@ -61,11 +61,6 @@
|
||||
unsigned. */
|
||||
#cmakedefine RIGHT_SHIFT_IS_UNSIGNED 1
|
||||
|
||||
/* Define to 1 if type `char' is unsigned and you are not using gcc. */
|
||||
#ifndef __CHAR_UNSIGNED__
|
||||
#cmakedefine __CHAR_UNSIGNED__ 1
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
|
||||
-1
@@ -18,7 +18,6 @@
|
||||
#define HAVE_UNSIGNED_SHORT
|
||||
#undef INCOMPLETE_TYPES_BROKEN
|
||||
#undef RIGHT_SHIFT_IS_UNSIGNED
|
||||
#undef __CHAR_UNSIGNED__
|
||||
|
||||
/* Define "boolean" as unsigned char, not int, per Windows custom */
|
||||
#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
|
||||
|
||||
+9
-9
@@ -48,9 +48,9 @@ rgb_ycc_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
outptr2 = output_buf[2][output_row];
|
||||
output_row++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
r = GETJSAMPLE(inptr[RGB_RED]);
|
||||
g = GETJSAMPLE(inptr[RGB_GREEN]);
|
||||
b = GETJSAMPLE(inptr[RGB_BLUE]);
|
||||
r = inptr[RGB_RED];
|
||||
g = inptr[RGB_GREEN];
|
||||
b = inptr[RGB_BLUE];
|
||||
inptr += RGB_PIXELSIZE;
|
||||
/* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
|
||||
* must be too; we do not need an explicit range-limiting operation.
|
||||
@@ -100,9 +100,9 @@ rgb_gray_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
outptr = output_buf[0][output_row];
|
||||
output_row++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
r = GETJSAMPLE(inptr[RGB_RED]);
|
||||
g = GETJSAMPLE(inptr[RGB_GREEN]);
|
||||
b = GETJSAMPLE(inptr[RGB_BLUE]);
|
||||
r = inptr[RGB_RED];
|
||||
g = inptr[RGB_GREEN];
|
||||
b = inptr[RGB_BLUE];
|
||||
inptr += RGB_PIXELSIZE;
|
||||
/* Y */
|
||||
outptr[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
|
||||
@@ -135,9 +135,9 @@ rgb_rgb_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
outptr2 = output_buf[2][output_row];
|
||||
output_row++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
outptr0[col] = GETJSAMPLE(inptr[RGB_RED]);
|
||||
outptr1[col] = GETJSAMPLE(inptr[RGB_GREEN]);
|
||||
outptr2[col] = GETJSAMPLE(inptr[RGB_BLUE]);
|
||||
outptr0[col] = inptr[RGB_RED];
|
||||
outptr1[col] = inptr[RGB_GREEN];
|
||||
outptr2[col] = inptr[RGB_BLUE];
|
||||
inptr += RGB_PIXELSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+6
-6
@@ -392,11 +392,11 @@ cmyk_ycck_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
outptr3 = output_buf[3][output_row];
|
||||
output_row++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
r = MAXJSAMPLE - GETJSAMPLE(inptr[0]);
|
||||
g = MAXJSAMPLE - GETJSAMPLE(inptr[1]);
|
||||
b = MAXJSAMPLE - GETJSAMPLE(inptr[2]);
|
||||
r = MAXJSAMPLE - inptr[0];
|
||||
g = MAXJSAMPLE - inptr[1];
|
||||
b = MAXJSAMPLE - inptr[2];
|
||||
/* K passes through as-is */
|
||||
outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */
|
||||
outptr3[col] = inptr[3];
|
||||
inptr += 4;
|
||||
/* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
|
||||
* must be too; we do not need an explicit range-limiting operation.
|
||||
@@ -438,7 +438,7 @@ grayscale_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
outptr = output_buf[0][output_row];
|
||||
output_row++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */
|
||||
outptr[col] = inptr[0];
|
||||
inptr += instride;
|
||||
}
|
||||
}
|
||||
@@ -497,7 +497,7 @@ null_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
|
||||
inptr = *input_buf;
|
||||
outptr = output_buf[ci][output_row];
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */
|
||||
outptr[col] = inptr[ci];
|
||||
inptr += nc;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-19
@@ -381,19 +381,19 @@ convsamp(JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM *workspace)
|
||||
elemptr = sample_data[elemr] + start_col;
|
||||
|
||||
#if DCTSIZE == 8 /* unroll the inner loop */
|
||||
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
|
||||
#else
|
||||
{
|
||||
register int elemc;
|
||||
for (elemc = DCTSIZE; elemc > 0; elemc--)
|
||||
*workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE;
|
||||
*workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -533,20 +533,19 @@ convsamp_float(JSAMPARRAY sample_data, JDIMENSION start_col,
|
||||
for (elemr = 0; elemr < DCTSIZE; elemr++) {
|
||||
elemptr = sample_data[elemr] + start_col;
|
||||
#if DCTSIZE == 8 /* unroll the inner loop */
|
||||
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
|
||||
#else
|
||||
{
|
||||
register int elemc;
|
||||
for (elemc = DCTSIZE; elemc > 0; elemc--)
|
||||
*workspaceptr++ = (FAST_FLOAT)
|
||||
(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
|
||||
*workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Vendored
+220
-180
@@ -4,8 +4,10 @@
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2009-2011, 2014-2016, 2018-2019, D. R. Commander.
|
||||
* Copyright (C) 2009-2011, 2014-2016, 2018-2021, D. R. Commander.
|
||||
* Copyright (C) 2015, Matthieu Darbois.
|
||||
* Copyright (C) 2018, Matthias Räncker.
|
||||
* Copyright (C) 2020, Arm Limited.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -42,15 +44,19 @@
|
||||
* flags (this defines __thumb__).
|
||||
*/
|
||||
|
||||
/* NOTE: Both GCC and Clang define __GNUC__ */
|
||||
#if defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))
|
||||
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || \
|
||||
defined(_M_ARM64)
|
||||
#if !defined(__thumb__) || defined(__thumb2__)
|
||||
#define USE_CLZ_INTRINSIC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLZ_INTRINSIC
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define JPEG_NBITS_NONZERO(x) (32 - _CountLeadingZeros(x))
|
||||
#else
|
||||
#define JPEG_NBITS_NONZERO(x) (32 - __builtin_clz(x))
|
||||
#endif
|
||||
#define JPEG_NBITS(x) (x ? JPEG_NBITS_NONZERO(x) : 0)
|
||||
#else
|
||||
#include "jpeg_nbits_table.h"
|
||||
@@ -65,32 +71,43 @@
|
||||
* but must not be updated permanently until we complete the MCU.
|
||||
*/
|
||||
|
||||
#if defined(__x86_64__) && defined(__ILP32__)
|
||||
typedef unsigned long long bit_buf_type;
|
||||
#else
|
||||
typedef size_t bit_buf_type;
|
||||
#endif
|
||||
|
||||
/* NOTE: The more optimal Huffman encoding algorithm is only used by the
|
||||
* intrinsics implementation of the Arm Neon SIMD extensions, which is why we
|
||||
* retain the old Huffman encoder behavior when using the GAS implementation.
|
||||
*/
|
||||
#if defined(WITH_SIMD) && !(defined(__arm__) || defined(__aarch64__) || \
|
||||
defined(_M_ARM) || defined(_M_ARM64))
|
||||
typedef unsigned long long simd_bit_buf_type;
|
||||
#else
|
||||
typedef bit_buf_type simd_bit_buf_type;
|
||||
#endif
|
||||
|
||||
#if (defined(SIZEOF_SIZE_T) && SIZEOF_SIZE_T == 8) || defined(_WIN64) || \
|
||||
(defined(__x86_64__) && defined(__ILP32__))
|
||||
#define BIT_BUF_SIZE 64
|
||||
#elif (defined(SIZEOF_SIZE_T) && SIZEOF_SIZE_T == 4) || defined(_WIN32)
|
||||
#define BIT_BUF_SIZE 32
|
||||
#else
|
||||
#error Cannot determine word size
|
||||
#endif
|
||||
#define SIMD_BIT_BUF_SIZE (sizeof(simd_bit_buf_type) * 8)
|
||||
|
||||
typedef struct {
|
||||
size_t put_buffer; /* current bit-accumulation buffer */
|
||||
int put_bits; /* # of bits now in it */
|
||||
union {
|
||||
bit_buf_type c;
|
||||
simd_bit_buf_type simd;
|
||||
} put_buffer; /* current bit accumulation buffer */
|
||||
int free_bits; /* # of bits available in it */
|
||||
/* (Neon GAS: # of bits now in it) */
|
||||
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
|
||||
} savable_state;
|
||||
|
||||
/* This macro is to work around compilers with missing or broken
|
||||
* structure assignment. You'll need to fix this code if you have
|
||||
* such a compiler and you change MAX_COMPS_IN_SCAN.
|
||||
*/
|
||||
|
||||
#ifndef NO_STRUCT_ASSIGN
|
||||
#define ASSIGN_STATE(dest, src) ((dest) = (src))
|
||||
#else
|
||||
#if MAX_COMPS_IN_SCAN == 4
|
||||
#define ASSIGN_STATE(dest, src) \
|
||||
((dest).put_buffer = (src).put_buffer, \
|
||||
(dest).put_bits = (src).put_bits, \
|
||||
(dest).last_dc_val[0] = (src).last_dc_val[0], \
|
||||
(dest).last_dc_val[1] = (src).last_dc_val[1], \
|
||||
(dest).last_dc_val[2] = (src).last_dc_val[2], \
|
||||
(dest).last_dc_val[3] = (src).last_dc_val[3])
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct jpeg_entropy_encoder pub; /* public fields */
|
||||
|
||||
@@ -123,6 +140,7 @@ typedef struct {
|
||||
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
|
||||
savable_state cur; /* Current bit buffer & DC state */
|
||||
j_compress_ptr cinfo; /* dump_buffer needs access to this */
|
||||
int simd;
|
||||
} working_state;
|
||||
|
||||
|
||||
@@ -201,8 +219,17 @@ start_pass_huff(j_compress_ptr cinfo, boolean gather_statistics)
|
||||
}
|
||||
|
||||
/* Initialize bit buffer to empty */
|
||||
entropy->saved.put_buffer = 0;
|
||||
entropy->saved.put_bits = 0;
|
||||
if (entropy->simd) {
|
||||
entropy->saved.put_buffer.simd = 0;
|
||||
#if defined(__aarch64__) && !defined(NEON_INTRINSICS)
|
||||
entropy->saved.free_bits = 0;
|
||||
#else
|
||||
entropy->saved.free_bits = SIMD_BIT_BUF_SIZE;
|
||||
#endif
|
||||
} else {
|
||||
entropy->saved.put_buffer.c = 0;
|
||||
entropy->saved.free_bits = BIT_BUF_SIZE;
|
||||
}
|
||||
|
||||
/* Initialize restart stuff */
|
||||
entropy->restarts_to_go = cinfo->restart_interval;
|
||||
@@ -287,6 +314,7 @@ jpeg_make_c_derived_tbl(j_compress_ptr cinfo, boolean isDC, int tblno,
|
||||
* this lets us detect duplicate VAL entries here, and later
|
||||
* allows emit_bits to detect any attempt to emit such symbols.
|
||||
*/
|
||||
MEMZERO(dtbl->ehufco, sizeof(dtbl->ehufco));
|
||||
MEMZERO(dtbl->ehufsi, sizeof(dtbl->ehufsi));
|
||||
|
||||
/* This is also a convenient place to check for out-of-range
|
||||
@@ -334,94 +362,94 @@ dump_buffer(working_state *state)
|
||||
|
||||
/* Outputting bits to the file */
|
||||
|
||||
/* These macros perform the same task as the emit_bits() function in the
|
||||
* original libjpeg code. In addition to reducing overhead by explicitly
|
||||
* inlining the code, additional performance is achieved by taking into
|
||||
* account the size of the bit buffer and waiting until it is almost full
|
||||
* before emptying it. This mostly benefits 64-bit platforms, since 6
|
||||
* bytes can be stored in a 64-bit bit buffer before it has to be emptied.
|
||||
/* Output byte b and, speculatively, an additional 0 byte. 0xFF must be
|
||||
* encoded as 0xFF 0x00, so the output buffer pointer is advanced by 2 if the
|
||||
* byte is 0xFF. Otherwise, the output buffer pointer is advanced by 1, and
|
||||
* the speculative 0 byte will be overwritten by the next byte.
|
||||
*/
|
||||
|
||||
#define EMIT_BYTE() { \
|
||||
JOCTET c; \
|
||||
put_bits -= 8; \
|
||||
c = (JOCTET)GETJOCTET(put_buffer >> put_bits); \
|
||||
*buffer++ = c; \
|
||||
if (c == 0xFF) /* need to stuff a zero byte? */ \
|
||||
*buffer++ = 0; \
|
||||
#define EMIT_BYTE(b) { \
|
||||
buffer[0] = (JOCTET)(b); \
|
||||
buffer[1] = 0; \
|
||||
buffer -= -2 + ((JOCTET)(b) < 0xFF); \
|
||||
}
|
||||
|
||||
#define PUT_BITS(code, size) { \
|
||||
put_bits += size; \
|
||||
put_buffer = (put_buffer << size) | code; \
|
||||
}
|
||||
/* Output the entire bit buffer. If there are no 0xFF bytes in it, then write
|
||||
* directly to the output buffer. Otherwise, use the EMIT_BYTE() macro to
|
||||
* encode 0xFF as 0xFF 0x00.
|
||||
*/
|
||||
#if BIT_BUF_SIZE == 64
|
||||
|
||||
#if SIZEOF_SIZE_T != 8 && !defined(_WIN64)
|
||||
|
||||
#define CHECKBUF15() { \
|
||||
if (put_bits > 15) { \
|
||||
EMIT_BYTE() \
|
||||
EMIT_BYTE() \
|
||||
#define FLUSH() { \
|
||||
if (put_buffer & 0x8080808080808080 & ~(put_buffer + 0x0101010101010101)) { \
|
||||
EMIT_BYTE(put_buffer >> 56) \
|
||||
EMIT_BYTE(put_buffer >> 48) \
|
||||
EMIT_BYTE(put_buffer >> 40) \
|
||||
EMIT_BYTE(put_buffer >> 32) \
|
||||
EMIT_BYTE(put_buffer >> 24) \
|
||||
EMIT_BYTE(put_buffer >> 16) \
|
||||
EMIT_BYTE(put_buffer >> 8) \
|
||||
EMIT_BYTE(put_buffer ) \
|
||||
} else { \
|
||||
buffer[0] = (JOCTET)(put_buffer >> 56); \
|
||||
buffer[1] = (JOCTET)(put_buffer >> 48); \
|
||||
buffer[2] = (JOCTET)(put_buffer >> 40); \
|
||||
buffer[3] = (JOCTET)(put_buffer >> 32); \
|
||||
buffer[4] = (JOCTET)(put_buffer >> 24); \
|
||||
buffer[5] = (JOCTET)(put_buffer >> 16); \
|
||||
buffer[6] = (JOCTET)(put_buffer >> 8); \
|
||||
buffer[7] = (JOCTET)(put_buffer); \
|
||||
buffer += 8; \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define CHECKBUF31() { \
|
||||
if (put_bits > 31) { \
|
||||
EMIT_BYTE() \
|
||||
EMIT_BYTE() \
|
||||
EMIT_BYTE() \
|
||||
EMIT_BYTE() \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECKBUF47() { \
|
||||
if (put_bits > 47) { \
|
||||
EMIT_BYTE() \
|
||||
EMIT_BYTE() \
|
||||
EMIT_BYTE() \
|
||||
EMIT_BYTE() \
|
||||
EMIT_BYTE() \
|
||||
EMIT_BYTE() \
|
||||
} \
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !defined(SIZEOF_SIZE_T)
|
||||
#error Cannot determine word size
|
||||
#endif
|
||||
|
||||
#if SIZEOF_SIZE_T == 8 || defined(_WIN64)
|
||||
|
||||
#define EMIT_BITS(code, size) { \
|
||||
CHECKBUF47() \
|
||||
PUT_BITS(code, size) \
|
||||
}
|
||||
|
||||
#define EMIT_CODE(code, size) { \
|
||||
temp2 &= (((JLONG)1) << nbits) - 1; \
|
||||
CHECKBUF31() \
|
||||
PUT_BITS(code, size) \
|
||||
PUT_BITS(temp2, nbits) \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define EMIT_BITS(code, size) { \
|
||||
PUT_BITS(code, size) \
|
||||
CHECKBUF15() \
|
||||
}
|
||||
|
||||
#define EMIT_CODE(code, size) { \
|
||||
temp2 &= (((JLONG)1) << nbits) - 1; \
|
||||
PUT_BITS(code, size) \
|
||||
CHECKBUF15() \
|
||||
PUT_BITS(temp2, nbits) \
|
||||
CHECKBUF15() \
|
||||
#define FLUSH() { \
|
||||
if (put_buffer & 0x80808080 & ~(put_buffer + 0x01010101)) { \
|
||||
EMIT_BYTE(put_buffer >> 24) \
|
||||
EMIT_BYTE(put_buffer >> 16) \
|
||||
EMIT_BYTE(put_buffer >> 8) \
|
||||
EMIT_BYTE(put_buffer ) \
|
||||
} else { \
|
||||
buffer[0] = (JOCTET)(put_buffer >> 24); \
|
||||
buffer[1] = (JOCTET)(put_buffer >> 16); \
|
||||
buffer[2] = (JOCTET)(put_buffer >> 8); \
|
||||
buffer[3] = (JOCTET)(put_buffer); \
|
||||
buffer += 4; \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Fill the bit buffer to capacity with the leading bits from code, then output
|
||||
* the bit buffer and put the remaining bits from code into the bit buffer.
|
||||
*/
|
||||
#define PUT_AND_FLUSH(code, size) { \
|
||||
put_buffer = (put_buffer << (size + free_bits)) | (code >> -free_bits); \
|
||||
FLUSH() \
|
||||
free_bits += BIT_BUF_SIZE; \
|
||||
put_buffer = code; \
|
||||
}
|
||||
|
||||
/* Insert code into the bit buffer and output the bit buffer if needed.
|
||||
* NOTE: We can't flush with free_bits == 0, since the left shift in
|
||||
* PUT_AND_FLUSH() would have undefined behavior.
|
||||
*/
|
||||
#define PUT_BITS(code, size) { \
|
||||
free_bits -= size; \
|
||||
if (free_bits < 0) \
|
||||
PUT_AND_FLUSH(code, size) \
|
||||
else \
|
||||
put_buffer = (put_buffer << size) | code; \
|
||||
}
|
||||
|
||||
#define PUT_CODE(code, size) { \
|
||||
temp &= (((JLONG)1) << nbits) - 1; \
|
||||
temp |= code << nbits; \
|
||||
nbits += size; \
|
||||
PUT_BITS(temp, nbits) \
|
||||
}
|
||||
|
||||
|
||||
/* Although it is exceedingly rare, it is possible for a Huffman-encoded
|
||||
* coefficient block to be larger than the 128-byte unencoded block. For each
|
||||
@@ -444,6 +472,7 @@ dump_buffer(working_state *state)
|
||||
|
||||
#define STORE_BUFFER() { \
|
||||
if (localbuf) { \
|
||||
size_t bytes, bytestocopy; \
|
||||
bytes = buffer - _buffer; \
|
||||
buffer = _buffer; \
|
||||
while (bytes > 0) { \
|
||||
@@ -466,20 +495,46 @@ dump_buffer(working_state *state)
|
||||
LOCAL(boolean)
|
||||
flush_bits(working_state *state)
|
||||
{
|
||||
JOCTET _buffer[BUFSIZE], *buffer;
|
||||
size_t put_buffer; int put_bits;
|
||||
size_t bytes, bytestocopy; int localbuf = 0;
|
||||
JOCTET _buffer[BUFSIZE], *buffer, temp;
|
||||
simd_bit_buf_type put_buffer; int put_bits;
|
||||
int localbuf = 0;
|
||||
|
||||
if (state->simd) {
|
||||
#if defined(__aarch64__) && !defined(NEON_INTRINSICS)
|
||||
put_bits = state->cur.free_bits;
|
||||
#else
|
||||
put_bits = SIMD_BIT_BUF_SIZE - state->cur.free_bits;
|
||||
#endif
|
||||
put_buffer = state->cur.put_buffer.simd;
|
||||
} else {
|
||||
put_bits = BIT_BUF_SIZE - state->cur.free_bits;
|
||||
put_buffer = state->cur.put_buffer.c;
|
||||
}
|
||||
|
||||
put_buffer = state->cur.put_buffer;
|
||||
put_bits = state->cur.put_bits;
|
||||
LOAD_BUFFER()
|
||||
|
||||
/* fill any partial byte with ones */
|
||||
PUT_BITS(0x7F, 7)
|
||||
while (put_bits >= 8) EMIT_BYTE()
|
||||
while (put_bits >= 8) {
|
||||
put_bits -= 8;
|
||||
temp = (JOCTET)(put_buffer >> put_bits);
|
||||
EMIT_BYTE(temp)
|
||||
}
|
||||
if (put_bits) {
|
||||
/* fill partial byte with ones */
|
||||
temp = (JOCTET)((put_buffer << (8 - put_bits)) | (0xFF >> put_bits));
|
||||
EMIT_BYTE(temp)
|
||||
}
|
||||
|
||||
state->cur.put_buffer = 0; /* and reset bit-buffer to empty */
|
||||
state->cur.put_bits = 0;
|
||||
if (state->simd) { /* and reset bit buffer to empty */
|
||||
state->cur.put_buffer.simd = 0;
|
||||
#if defined(__aarch64__) && !defined(NEON_INTRINSICS)
|
||||
state->cur.free_bits = 0;
|
||||
#else
|
||||
state->cur.free_bits = SIMD_BIT_BUF_SIZE;
|
||||
#endif
|
||||
} else {
|
||||
state->cur.put_buffer.c = 0;
|
||||
state->cur.free_bits = BIT_BUF_SIZE;
|
||||
}
|
||||
STORE_BUFFER()
|
||||
|
||||
return TRUE;
|
||||
@@ -493,7 +548,7 @@ encode_one_block_simd(working_state *state, JCOEFPTR block, int last_dc_val,
|
||||
c_derived_tbl *dctbl, c_derived_tbl *actbl)
|
||||
{
|
||||
JOCTET _buffer[BUFSIZE], *buffer;
|
||||
size_t bytes, bytestocopy; int localbuf = 0;
|
||||
int localbuf = 0;
|
||||
|
||||
LOAD_BUFFER()
|
||||
|
||||
@@ -509,53 +564,41 @@ LOCAL(boolean)
|
||||
encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
|
||||
c_derived_tbl *dctbl, c_derived_tbl *actbl)
|
||||
{
|
||||
int temp, temp2, temp3;
|
||||
int nbits;
|
||||
int r, code, size;
|
||||
int temp, nbits, free_bits;
|
||||
bit_buf_type put_buffer;
|
||||
JOCTET _buffer[BUFSIZE], *buffer;
|
||||
size_t put_buffer; int put_bits;
|
||||
int code_0xf0 = actbl->ehufco[0xf0], size_0xf0 = actbl->ehufsi[0xf0];
|
||||
size_t bytes, bytestocopy; int localbuf = 0;
|
||||
int localbuf = 0;
|
||||
|
||||
put_buffer = state->cur.put_buffer;
|
||||
put_bits = state->cur.put_bits;
|
||||
free_bits = state->cur.free_bits;
|
||||
put_buffer = state->cur.put_buffer.c;
|
||||
LOAD_BUFFER()
|
||||
|
||||
/* Encode the DC coefficient difference per section F.1.2.1 */
|
||||
|
||||
temp = temp2 = block[0] - last_dc_val;
|
||||
temp = block[0] - last_dc_val;
|
||||
|
||||
/* This is a well-known technique for obtaining the absolute value without a
|
||||
* branch. It is derived from an assembly language technique presented in
|
||||
* "How to Optimize for the Pentium Processors", Copyright (c) 1996, 1997 by
|
||||
* Agner Fog.
|
||||
* Agner Fog. This code assumes we are on a two's complement machine.
|
||||
*/
|
||||
temp3 = temp >> (CHAR_BIT * sizeof(int) - 1);
|
||||
temp ^= temp3;
|
||||
temp -= temp3;
|
||||
|
||||
/* For a negative input, want temp2 = bitwise complement of abs(input) */
|
||||
/* This code assumes we are on a two's complement machine */
|
||||
temp2 += temp3;
|
||||
nbits = temp >> (CHAR_BIT * sizeof(int) - 1);
|
||||
temp += nbits;
|
||||
nbits ^= temp;
|
||||
|
||||
/* Find the number of bits needed for the magnitude of the coefficient */
|
||||
nbits = JPEG_NBITS(temp);
|
||||
nbits = JPEG_NBITS(nbits);
|
||||
|
||||
/* Emit the Huffman-coded symbol for the number of bits */
|
||||
code = dctbl->ehufco[nbits];
|
||||
size = dctbl->ehufsi[nbits];
|
||||
EMIT_BITS(code, size)
|
||||
|
||||
/* Mask off any extra bits in code */
|
||||
temp2 &= (((JLONG)1) << nbits) - 1;
|
||||
|
||||
/* Emit that number of bits of the value, if positive, */
|
||||
/* or the complement of its magnitude, if negative. */
|
||||
EMIT_BITS(temp2, nbits)
|
||||
/* Emit the Huffman-coded symbol for the number of bits.
|
||||
* Emit that number of bits of the value, if positive,
|
||||
* or the complement of its magnitude, if negative.
|
||||
*/
|
||||
PUT_CODE(dctbl->ehufco[nbits], dctbl->ehufsi[nbits])
|
||||
|
||||
/* Encode the AC coefficients per section F.1.2.2 */
|
||||
|
||||
r = 0; /* r = run length of zeros */
|
||||
{
|
||||
int r = 0; /* r = run length of zeros */
|
||||
|
||||
/* Manually unroll the k loop to eliminate the counter variable. This
|
||||
* improves performance greatly on systems with a limited number of
|
||||
@@ -563,51 +606,46 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
|
||||
*/
|
||||
#define kloop(jpeg_natural_order_of_k) { \
|
||||
if ((temp = block[jpeg_natural_order_of_k]) == 0) { \
|
||||
r++; \
|
||||
r += 16; \
|
||||
} else { \
|
||||
temp2 = temp; \
|
||||
/* Branch-less absolute value, bitwise complement, etc., same as above */ \
|
||||
temp3 = temp >> (CHAR_BIT * sizeof(int) - 1); \
|
||||
temp ^= temp3; \
|
||||
temp -= temp3; \
|
||||
temp2 += temp3; \
|
||||
nbits = JPEG_NBITS_NONZERO(temp); \
|
||||
nbits = temp >> (CHAR_BIT * sizeof(int) - 1); \
|
||||
temp += nbits; \
|
||||
nbits ^= temp; \
|
||||
nbits = JPEG_NBITS_NONZERO(nbits); \
|
||||
/* if run length > 15, must emit special run-length-16 codes (0xF0) */ \
|
||||
while (r > 15) { \
|
||||
EMIT_BITS(code_0xf0, size_0xf0) \
|
||||
r -= 16; \
|
||||
while (r >= 16 * 16) { \
|
||||
r -= 16 * 16; \
|
||||
PUT_BITS(actbl->ehufco[0xf0], actbl->ehufsi[0xf0]) \
|
||||
} \
|
||||
/* Emit Huffman symbol for run length / number of bits */ \
|
||||
temp3 = (r << 4) + nbits; \
|
||||
code = actbl->ehufco[temp3]; \
|
||||
size = actbl->ehufsi[temp3]; \
|
||||
EMIT_CODE(code, size) \
|
||||
r += nbits; \
|
||||
PUT_CODE(actbl->ehufco[r], actbl->ehufsi[r]) \
|
||||
r = 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* One iteration for each value in jpeg_natural_order[] */
|
||||
kloop(1); kloop(8); kloop(16); kloop(9); kloop(2); kloop(3);
|
||||
kloop(10); kloop(17); kloop(24); kloop(32); kloop(25); kloop(18);
|
||||
kloop(11); kloop(4); kloop(5); kloop(12); kloop(19); kloop(26);
|
||||
kloop(33); kloop(40); kloop(48); kloop(41); kloop(34); kloop(27);
|
||||
kloop(20); kloop(13); kloop(6); kloop(7); kloop(14); kloop(21);
|
||||
kloop(28); kloop(35); kloop(42); kloop(49); kloop(56); kloop(57);
|
||||
kloop(50); kloop(43); kloop(36); kloop(29); kloop(22); kloop(15);
|
||||
kloop(23); kloop(30); kloop(37); kloop(44); kloop(51); kloop(58);
|
||||
kloop(59); kloop(52); kloop(45); kloop(38); kloop(31); kloop(39);
|
||||
kloop(46); kloop(53); kloop(60); kloop(61); kloop(54); kloop(47);
|
||||
kloop(55); kloop(62); kloop(63);
|
||||
/* One iteration for each value in jpeg_natural_order[] */
|
||||
kloop(1); kloop(8); kloop(16); kloop(9); kloop(2); kloop(3);
|
||||
kloop(10); kloop(17); kloop(24); kloop(32); kloop(25); kloop(18);
|
||||
kloop(11); kloop(4); kloop(5); kloop(12); kloop(19); kloop(26);
|
||||
kloop(33); kloop(40); kloop(48); kloop(41); kloop(34); kloop(27);
|
||||
kloop(20); kloop(13); kloop(6); kloop(7); kloop(14); kloop(21);
|
||||
kloop(28); kloop(35); kloop(42); kloop(49); kloop(56); kloop(57);
|
||||
kloop(50); kloop(43); kloop(36); kloop(29); kloop(22); kloop(15);
|
||||
kloop(23); kloop(30); kloop(37); kloop(44); kloop(51); kloop(58);
|
||||
kloop(59); kloop(52); kloop(45); kloop(38); kloop(31); kloop(39);
|
||||
kloop(46); kloop(53); kloop(60); kloop(61); kloop(54); kloop(47);
|
||||
kloop(55); kloop(62); kloop(63);
|
||||
|
||||
/* If the last coef(s) were zero, emit an end-of-block code */
|
||||
if (r > 0) {
|
||||
code = actbl->ehufco[0];
|
||||
size = actbl->ehufsi[0];
|
||||
EMIT_BITS(code, size)
|
||||
/* If the last coef(s) were zero, emit an end-of-block code */
|
||||
if (r > 0) {
|
||||
PUT_BITS(actbl->ehufco[0], actbl->ehufsi[0])
|
||||
}
|
||||
}
|
||||
|
||||
state->cur.put_buffer = put_buffer;
|
||||
state->cur.put_bits = put_bits;
|
||||
state->cur.put_buffer.c = put_buffer;
|
||||
state->cur.free_bits = free_bits;
|
||||
STORE_BUFFER()
|
||||
|
||||
return TRUE;
|
||||
@@ -654,8 +692,9 @@ encode_mcu_huff(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
/* Load up working state */
|
||||
state.next_output_byte = cinfo->dest->next_output_byte;
|
||||
state.free_in_buffer = cinfo->dest->free_in_buffer;
|
||||
ASSIGN_STATE(state.cur, entropy->saved);
|
||||
state.cur = entropy->saved;
|
||||
state.cinfo = cinfo;
|
||||
state.simd = entropy->simd;
|
||||
|
||||
/* Emit restart marker if needed */
|
||||
if (cinfo->restart_interval) {
|
||||
@@ -694,7 +733,7 @@ encode_mcu_huff(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
/* Completed MCU, so update state */
|
||||
cinfo->dest->next_output_byte = state.next_output_byte;
|
||||
cinfo->dest->free_in_buffer = state.free_in_buffer;
|
||||
ASSIGN_STATE(entropy->saved, state.cur);
|
||||
entropy->saved = state.cur;
|
||||
|
||||
/* Update restart-interval state too */
|
||||
if (cinfo->restart_interval) {
|
||||
@@ -723,8 +762,9 @@ finish_pass_huff(j_compress_ptr cinfo)
|
||||
/* Load up working state ... flush_bits needs it */
|
||||
state.next_output_byte = cinfo->dest->next_output_byte;
|
||||
state.free_in_buffer = cinfo->dest->free_in_buffer;
|
||||
ASSIGN_STATE(state.cur, entropy->saved);
|
||||
state.cur = entropy->saved;
|
||||
state.cinfo = cinfo;
|
||||
state.simd = entropy->simd;
|
||||
|
||||
/* Flush out the last data */
|
||||
if (!flush_bits(&state))
|
||||
@@ -733,7 +773,7 @@ finish_pass_huff(j_compress_ptr cinfo)
|
||||
/* Update state */
|
||||
cinfo->dest->next_output_byte = state.next_output_byte;
|
||||
cinfo->dest->free_in_buffer = state.free_in_buffer;
|
||||
ASSIGN_STATE(entropy->saved, state.cur);
|
||||
entropy->saved = state.cur;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vendored
+16
-9
@@ -4,8 +4,9 @@
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Copyright (C) 1995-1997, Thomas G. Lane.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2011, 2015, 2018, D. R. Commander.
|
||||
* Copyright (C) 2011, 2015, 2018, 2021, D. R. Commander.
|
||||
* Copyright (C) 2016, 2018, Matthieu Darbois.
|
||||
* Copyright (C) 2020, Arm Limited.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -51,15 +52,19 @@
|
||||
* flags (this defines __thumb__).
|
||||
*/
|
||||
|
||||
/* NOTE: Both GCC and Clang define __GNUC__ */
|
||||
#if defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))
|
||||
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || \
|
||||
defined(_M_ARM64)
|
||||
#if !defined(__thumb__) || defined(__thumb2__)
|
||||
#define USE_CLZ_INTRINSIC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLZ_INTRINSIC
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define JPEG_NBITS_NONZERO(x) (32 - _CountLeadingZeros(x))
|
||||
#else
|
||||
#define JPEG_NBITS_NONZERO(x) (32 - __builtin_clz(x))
|
||||
#endif
|
||||
#define JPEG_NBITS(x) (x ? JPEG_NBITS_NONZERO(x) : 0)
|
||||
#else
|
||||
#include "jpeg_nbits_table.h"
|
||||
@@ -169,24 +174,26 @@ INLINE
|
||||
METHODDEF(int)
|
||||
count_zeroes(size_t *x)
|
||||
{
|
||||
int result;
|
||||
#if defined(HAVE_BUILTIN_CTZL)
|
||||
int result;
|
||||
result = __builtin_ctzl(*x);
|
||||
*x >>= result;
|
||||
#elif defined(HAVE_BITSCANFORWARD64)
|
||||
unsigned long result;
|
||||
_BitScanForward64(&result, *x);
|
||||
*x >>= result;
|
||||
#elif defined(HAVE_BITSCANFORWARD)
|
||||
unsigned long result;
|
||||
_BitScanForward(&result, *x);
|
||||
*x >>= result;
|
||||
#else
|
||||
result = 0;
|
||||
int result = 0;
|
||||
while ((*x & 1) == 0) {
|
||||
++result;
|
||||
*x >>= 1;
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
|
||||
@@ -860,7 +867,7 @@ encode_mcu_AC_refine_prepare(const JCOEF *block,
|
||||
|
||||
#define ENCODE_COEFS_AC_REFINE(label) { \
|
||||
while (zerobits) { \
|
||||
int idx = count_zeroes(&zerobits); \
|
||||
idx = count_zeroes(&zerobits); \
|
||||
r += idx; \
|
||||
cabsvalue += idx; \
|
||||
signbits >>= idx; \
|
||||
@@ -917,7 +924,7 @@ METHODDEF(boolean)
|
||||
encode_mcu_AC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
{
|
||||
phuff_entropy_ptr entropy = (phuff_entropy_ptr)cinfo->entropy;
|
||||
register int temp, r;
|
||||
register int temp, r, idx;
|
||||
char *BR_buffer;
|
||||
unsigned int BR;
|
||||
int Sl = cinfo->Se - cinfo->Ss + 1;
|
||||
@@ -968,7 +975,7 @@ encode_mcu_AC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
|
||||
if (zerobits) {
|
||||
int diff = ((absvalues + DCTSIZE2 / 2) - cabsvalue);
|
||||
int idx = count_zeroes(&zerobits);
|
||||
idx = count_zeroes(&zerobits);
|
||||
signbits >>= idx;
|
||||
idx += diff;
|
||||
r += idx;
|
||||
|
||||
+23
-40
@@ -6,7 +6,7 @@
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||
* Copyright (C) 2014, MIPS Technologies, Inc., California.
|
||||
* Copyright (C) 2015, D. R. Commander.
|
||||
* Copyright (C) 2015, 2019, D. R. Commander.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -103,7 +103,7 @@ expand_right_edge(JSAMPARRAY image_data, int num_rows, JDIMENSION input_cols,
|
||||
if (numcols > 0) {
|
||||
for (row = 0; row < num_rows; row++) {
|
||||
ptr = image_data[row] + input_cols;
|
||||
pixval = ptr[-1]; /* don't need GETJSAMPLE() here */
|
||||
pixval = ptr[-1];
|
||||
for (count = numcols; count > 0; count--)
|
||||
*ptr++ = pixval;
|
||||
}
|
||||
@@ -174,7 +174,7 @@ int_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||
for (v = 0; v < v_expand; v++) {
|
||||
inptr = input_data[inrow + v] + outcol_h;
|
||||
for (h = 0; h < h_expand; h++) {
|
||||
outvalue += (JLONG)GETJSAMPLE(*inptr++);
|
||||
outvalue += (JLONG)(*inptr++);
|
||||
}
|
||||
}
|
||||
*outptr++ = (JSAMPLE)((outvalue + numpix2) / numpix);
|
||||
@@ -237,8 +237,7 @@ h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||
inptr = input_data[outrow];
|
||||
bias = 0; /* bias = 0,1,0,1,... for successive samples */
|
||||
for (outcol = 0; outcol < output_cols; outcol++) {
|
||||
*outptr++ =
|
||||
(JSAMPLE)((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1]) + bias) >> 1);
|
||||
*outptr++ = (JSAMPLE)((inptr[0] + inptr[1] + bias) >> 1);
|
||||
bias ^= 1; /* 0=>1, 1=>0 */
|
||||
inptr += 2;
|
||||
}
|
||||
@@ -277,8 +276,7 @@ h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||
bias = 1; /* bias = 1,2,1,2,... for successive samples */
|
||||
for (outcol = 0; outcol < output_cols; outcol++) {
|
||||
*outptr++ =
|
||||
(JSAMPLE)((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
|
||||
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]) + bias) >> 2);
|
||||
(JSAMPLE)((inptr0[0] + inptr0[1] + inptr1[0] + inptr1[1] + bias) >> 2);
|
||||
bias ^= 3; /* 1=>2, 2=>1 */
|
||||
inptr0 += 2; inptr1 += 2;
|
||||
}
|
||||
@@ -337,33 +335,25 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||
below_ptr = input_data[inrow + 2];
|
||||
|
||||
/* Special case for first column: pretend column -1 is same as column 0 */
|
||||
membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
|
||||
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
|
||||
neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
|
||||
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
|
||||
GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) +
|
||||
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]);
|
||||
membersum = inptr0[0] + inptr0[1] + inptr1[0] + inptr1[1];
|
||||
neighsum = above_ptr[0] + above_ptr[1] + below_ptr[0] + below_ptr[1] +
|
||||
inptr0[0] + inptr0[2] + inptr1[0] + inptr1[2];
|
||||
neighsum += neighsum;
|
||||
neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) +
|
||||
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]);
|
||||
neighsum += above_ptr[0] + above_ptr[2] + below_ptr[0] + below_ptr[2];
|
||||
membersum = membersum * memberscale + neighsum * neighscale;
|
||||
*outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
|
||||
inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
|
||||
|
||||
for (colctr = output_cols - 2; colctr > 0; colctr--) {
|
||||
/* sum of pixels directly mapped to this output element */
|
||||
membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
|
||||
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
|
||||
membersum = inptr0[0] + inptr0[1] + inptr1[0] + inptr1[1];
|
||||
/* sum of edge-neighbor pixels */
|
||||
neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
|
||||
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
|
||||
GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) +
|
||||
GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]);
|
||||
neighsum = above_ptr[0] + above_ptr[1] + below_ptr[0] + below_ptr[1] +
|
||||
inptr0[-1] + inptr0[2] + inptr1[-1] + inptr1[2];
|
||||
/* The edge-neighbors count twice as much as corner-neighbors */
|
||||
neighsum += neighsum;
|
||||
/* Add in the corner-neighbors */
|
||||
neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) +
|
||||
GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]);
|
||||
neighsum += above_ptr[-1] + above_ptr[2] + below_ptr[-1] + below_ptr[2];
|
||||
/* form final output scaled up by 2^16 */
|
||||
membersum = membersum * memberscale + neighsum * neighscale;
|
||||
/* round, descale and output it */
|
||||
@@ -372,15 +362,11 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||
}
|
||||
|
||||
/* Special case for last column */
|
||||
membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
|
||||
GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
|
||||
neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
|
||||
GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
|
||||
GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) +
|
||||
GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]);
|
||||
membersum = inptr0[0] + inptr0[1] + inptr1[0] + inptr1[1];
|
||||
neighsum = above_ptr[0] + above_ptr[1] + below_ptr[0] + below_ptr[1] +
|
||||
inptr0[-1] + inptr0[1] + inptr1[-1] + inptr1[1];
|
||||
neighsum += neighsum;
|
||||
neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) +
|
||||
GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]);
|
||||
neighsum += above_ptr[-1] + above_ptr[1] + below_ptr[-1] + below_ptr[1];
|
||||
membersum = membersum * memberscale + neighsum * neighscale;
|
||||
*outptr = (JSAMPLE)((membersum + 32768) >> 16);
|
||||
|
||||
@@ -429,21 +415,18 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||
below_ptr = input_data[outrow + 1];
|
||||
|
||||
/* Special case for first column */
|
||||
colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) +
|
||||
GETJSAMPLE(*inptr);
|
||||
membersum = GETJSAMPLE(*inptr++);
|
||||
nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
|
||||
GETJSAMPLE(*inptr);
|
||||
colsum = (*above_ptr++) + (*below_ptr++) + inptr[0];
|
||||
membersum = *inptr++;
|
||||
nextcolsum = above_ptr[0] + below_ptr[0] + inptr[0];
|
||||
neighsum = colsum + (colsum - membersum) + nextcolsum;
|
||||
membersum = membersum * memberscale + neighsum * neighscale;
|
||||
*outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
|
||||
lastcolsum = colsum; colsum = nextcolsum;
|
||||
|
||||
for (colctr = output_cols - 2; colctr > 0; colctr--) {
|
||||
membersum = GETJSAMPLE(*inptr++);
|
||||
membersum = *inptr++;
|
||||
above_ptr++; below_ptr++;
|
||||
nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
|
||||
GETJSAMPLE(*inptr);
|
||||
nextcolsum = above_ptr[0] + below_ptr[0] + inptr[0];
|
||||
neighsum = lastcolsum + (colsum - membersum) + nextcolsum;
|
||||
membersum = membersum * memberscale + neighsum * neighscale;
|
||||
*outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
|
||||
@@ -451,7 +434,7 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
|
||||
}
|
||||
|
||||
/* Special case for last column */
|
||||
membersum = GETJSAMPLE(*inptr);
|
||||
membersum = *inptr;
|
||||
neighsum = lastcolsum + (colsum - membersum) + colsum;
|
||||
membersum = membersum * memberscale + neighsum * neighscale;
|
||||
*outptr = (JSAMPLE)((membersum + 32768) >> 16);
|
||||
|
||||
+9
-1
@@ -4,7 +4,7 @@
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Copyright (C) 1994-1996, Thomas G. Lane.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2010, 2015-2018, 2020, D. R. Commander.
|
||||
* Copyright (C) 2010, 2015-2020, D. R. Commander.
|
||||
* Copyright (C) 2015, Google, Inc.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
@@ -319,6 +319,8 @@ read_and_discard_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
|
||||
{
|
||||
JDIMENSION n;
|
||||
my_master_ptr master = (my_master_ptr)cinfo->master;
|
||||
JSAMPLE dummy_sample[1] = { 0 };
|
||||
JSAMPROW dummy_row = dummy_sample;
|
||||
JSAMPARRAY scanlines = NULL;
|
||||
void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
JDIMENSION input_row, JSAMPARRAY output_buf,
|
||||
@@ -329,6 +331,10 @@ read_and_discard_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
|
||||
if (cinfo->cconvert && cinfo->cconvert->color_convert) {
|
||||
color_convert = cinfo->cconvert->color_convert;
|
||||
cinfo->cconvert->color_convert = noop_convert;
|
||||
/* This just prevents UBSan from complaining about adding 0 to a NULL
|
||||
* pointer. The pointer isn't actually used.
|
||||
*/
|
||||
scanlines = &dummy_row;
|
||||
}
|
||||
|
||||
if (cinfo->cquantize && cinfo->cquantize->color_quantize) {
|
||||
@@ -532,6 +538,8 @@ jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
|
||||
* decoded coefficients. This is ~5% faster for large subsets, but
|
||||
* it's tough to tell a difference for smaller images.
|
||||
*/
|
||||
if (!cinfo->entropy->insufficient_data)
|
||||
cinfo->master->last_good_iMCU_row = cinfo->input_iMCU_row;
|
||||
(*cinfo->entropy->decode_mcu) (cinfo, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+12
-3
@@ -4,7 +4,7 @@
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Developed 1997-2015 by Guido Vollbeding.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2015-2018, D. R. Commander.
|
||||
* Copyright (C) 2015-2020, D. R. Commander.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -80,7 +80,7 @@ get_byte(j_decompress_ptr cinfo)
|
||||
if (!(*src->fill_input_buffer) (cinfo))
|
||||
ERREXIT(cinfo, JERR_CANT_SUSPEND);
|
||||
src->bytes_in_buffer--;
|
||||
return GETJOCTET(*src->next_input_byte++);
|
||||
return *src->next_input_byte++;
|
||||
}
|
||||
|
||||
|
||||
@@ -665,8 +665,16 @@ bad:
|
||||
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
||||
int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;
|
||||
int *coef_bit_ptr = &cinfo->coef_bits[cindex][0];
|
||||
int *prev_coef_bit_ptr =
|
||||
&cinfo->coef_bits[cindex + cinfo->num_components][0];
|
||||
if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
|
||||
WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
|
||||
for (coefi = MIN(cinfo->Ss, 1); coefi <= MAX(cinfo->Se, 9); coefi++) {
|
||||
if (cinfo->input_scan_number > 1)
|
||||
prev_coef_bit_ptr[coefi] = coef_bit_ptr[coefi];
|
||||
else
|
||||
prev_coef_bit_ptr[coefi] = 0;
|
||||
}
|
||||
for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
|
||||
int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
|
||||
if (cinfo->Ah != expected)
|
||||
@@ -727,6 +735,7 @@ bad:
|
||||
entropy->c = 0;
|
||||
entropy->a = 0;
|
||||
entropy->ct = -16; /* force reading 2 initial bytes to fill C */
|
||||
entropy->pub.insufficient_data = FALSE;
|
||||
|
||||
/* Initialize restart counter */
|
||||
entropy->restarts_to_go = cinfo->restart_interval;
|
||||
@@ -763,7 +772,7 @@ jinit_arith_decoder(j_decompress_ptr cinfo)
|
||||
int *coef_bit_ptr, ci;
|
||||
cinfo->coef_bits = (int (*)[DCTSIZE2])
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
|
||||
cinfo->num_components * DCTSIZE2 *
|
||||
cinfo->num_components * 2 * DCTSIZE2 *
|
||||
sizeof(int));
|
||||
coef_bit_ptr = &cinfo->coef_bits[0][0];
|
||||
for (ci = 0; ci < cinfo->num_components; ci++)
|
||||
|
||||
+237
-53
@@ -5,7 +5,7 @@
|
||||
* Copyright (C) 1994-1997, Thomas G. Lane.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||
* Copyright (C) 2010, 2015-2016, D. R. Commander.
|
||||
* Copyright (C) 2010, 2015-2016, 2019-2020, D. R. Commander.
|
||||
* Copyright (C) 2015, 2020, Google, Inc.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
@@ -102,6 +102,8 @@ decompress_onepass(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
/* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */
|
||||
jzero_far((void *)coef->MCU_buffer[0],
|
||||
(size_t)(cinfo->blocks_in_MCU * sizeof(JBLOCK)));
|
||||
if (!cinfo->entropy->insufficient_data)
|
||||
cinfo->master->last_good_iMCU_row = cinfo->input_iMCU_row;
|
||||
if (!(*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
|
||||
/* Suspension forced; update state counters and exit */
|
||||
coef->MCU_vert_offset = yoffset;
|
||||
@@ -227,6 +229,8 @@ consume_data(j_decompress_ptr cinfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cinfo->entropy->insufficient_data)
|
||||
cinfo->master->last_good_iMCU_row = cinfo->input_iMCU_row;
|
||||
/* Try to fetch the MCU. */
|
||||
if (!(*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
|
||||
/* Suspension forced; update state counters and exit */
|
||||
@@ -326,19 +330,22 @@ decompress_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
#ifdef BLOCK_SMOOTHING_SUPPORTED
|
||||
|
||||
/*
|
||||
* This code applies interblock smoothing as described by section K.8
|
||||
* of the JPEG standard: the first 5 AC coefficients are estimated from
|
||||
* the DC values of a DCT block and its 8 neighboring blocks.
|
||||
* This code applies interblock smoothing; the first 9 AC coefficients are
|
||||
* estimated from the DC values of a DCT block and its 24 neighboring blocks.
|
||||
* We apply smoothing only for progressive JPEG decoding, and only if
|
||||
* the coefficients it can estimate are not yet known to full precision.
|
||||
*/
|
||||
|
||||
/* Natural-order array positions of the first 5 zigzag-order coefficients */
|
||||
/* Natural-order array positions of the first 9 zigzag-order coefficients */
|
||||
#define Q01_POS 1
|
||||
#define Q10_POS 8
|
||||
#define Q20_POS 16
|
||||
#define Q11_POS 9
|
||||
#define Q02_POS 2
|
||||
#define Q03_POS 3
|
||||
#define Q12_POS 10
|
||||
#define Q21_POS 17
|
||||
#define Q30_POS 24
|
||||
|
||||
/*
|
||||
* Determine whether block smoothing is applicable and safe.
|
||||
@@ -356,8 +363,8 @@ smoothing_ok(j_decompress_ptr cinfo)
|
||||
int ci, coefi;
|
||||
jpeg_component_info *compptr;
|
||||
JQUANT_TBL *qtable;
|
||||
int *coef_bits;
|
||||
int *coef_bits_latch;
|
||||
int *coef_bits, *prev_coef_bits;
|
||||
int *coef_bits_latch, *prev_coef_bits_latch;
|
||||
|
||||
if (!cinfo->progressive_mode || cinfo->coef_bits == NULL)
|
||||
return FALSE;
|
||||
@@ -366,34 +373,47 @@ smoothing_ok(j_decompress_ptr cinfo)
|
||||
if (coef->coef_bits_latch == NULL)
|
||||
coef->coef_bits_latch = (int *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
|
||||
cinfo->num_components *
|
||||
cinfo->num_components * 2 *
|
||||
(SAVED_COEFS * sizeof(int)));
|
||||
coef_bits_latch = coef->coef_bits_latch;
|
||||
prev_coef_bits_latch =
|
||||
&coef->coef_bits_latch[cinfo->num_components * SAVED_COEFS];
|
||||
|
||||
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
||||
ci++, compptr++) {
|
||||
/* All components' quantization values must already be latched. */
|
||||
if ((qtable = compptr->quant_table) == NULL)
|
||||
return FALSE;
|
||||
/* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */
|
||||
/* Verify DC & first 9 AC quantizers are nonzero to avoid zero-divide. */
|
||||
if (qtable->quantval[0] == 0 ||
|
||||
qtable->quantval[Q01_POS] == 0 ||
|
||||
qtable->quantval[Q10_POS] == 0 ||
|
||||
qtable->quantval[Q20_POS] == 0 ||
|
||||
qtable->quantval[Q11_POS] == 0 ||
|
||||
qtable->quantval[Q02_POS] == 0)
|
||||
qtable->quantval[Q02_POS] == 0 ||
|
||||
qtable->quantval[Q03_POS] == 0 ||
|
||||
qtable->quantval[Q12_POS] == 0 ||
|
||||
qtable->quantval[Q21_POS] == 0 ||
|
||||
qtable->quantval[Q30_POS] == 0)
|
||||
return FALSE;
|
||||
/* DC values must be at least partly known for all components. */
|
||||
coef_bits = cinfo->coef_bits[ci];
|
||||
prev_coef_bits = cinfo->coef_bits[ci + cinfo->num_components];
|
||||
if (coef_bits[0] < 0)
|
||||
return FALSE;
|
||||
coef_bits_latch[0] = coef_bits[0];
|
||||
/* Block smoothing is helpful if some AC coefficients remain inaccurate. */
|
||||
for (coefi = 1; coefi <= 5; coefi++) {
|
||||
for (coefi = 1; coefi < SAVED_COEFS; coefi++) {
|
||||
if (cinfo->input_scan_number > 1)
|
||||
prev_coef_bits_latch[coefi] = prev_coef_bits[coefi];
|
||||
else
|
||||
prev_coef_bits_latch[coefi] = -1;
|
||||
coef_bits_latch[coefi] = coef_bits[coefi];
|
||||
if (coef_bits[coefi] != 0)
|
||||
smoothing_useful = TRUE;
|
||||
}
|
||||
coef_bits_latch += SAVED_COEFS;
|
||||
prev_coef_bits_latch += SAVED_COEFS;
|
||||
}
|
||||
|
||||
return smoothing_useful;
|
||||
@@ -412,17 +432,20 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
JDIMENSION block_num, last_block_column;
|
||||
int ci, block_row, block_rows, access_rows;
|
||||
JBLOCKARRAY buffer;
|
||||
JBLOCKROW buffer_ptr, prev_block_row, next_block_row;
|
||||
JBLOCKROW buffer_ptr, prev_prev_block_row, prev_block_row;
|
||||
JBLOCKROW next_block_row, next_next_block_row;
|
||||
JSAMPARRAY output_ptr;
|
||||
JDIMENSION output_col;
|
||||
jpeg_component_info *compptr;
|
||||
inverse_DCT_method_ptr inverse_DCT;
|
||||
boolean first_row, last_row;
|
||||
boolean change_dc;
|
||||
JCOEF *workspace;
|
||||
int *coef_bits;
|
||||
JQUANT_TBL *quanttbl;
|
||||
JLONG Q00, Q01, Q02, Q10, Q11, Q20, num;
|
||||
int DC1, DC2, DC3, DC4, DC5, DC6, DC7, DC8, DC9;
|
||||
JLONG Q00, Q01, Q02, Q03 = 0, Q10, Q11, Q12 = 0, Q20, Q21 = 0, Q30 = 0, num;
|
||||
int DC01, DC02, DC03, DC04, DC05, DC06, DC07, DC08, DC09, DC10, DC11, DC12,
|
||||
DC13, DC14, DC15, DC16, DC17, DC18, DC19, DC20, DC21, DC22, DC23, DC24,
|
||||
DC25;
|
||||
int Al, pred;
|
||||
|
||||
/* Keep a local variable to avoid looking it up more than once */
|
||||
@@ -434,10 +457,10 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
if (cinfo->input_scan_number == cinfo->output_scan_number) {
|
||||
/* If input is working on current scan, we ordinarily want it to
|
||||
* have completed the current row. But if input scan is DC,
|
||||
* we want it to keep one row ahead so that next block row's DC
|
||||
* we want it to keep two rows ahead so that next two block rows' DC
|
||||
* values are up to date.
|
||||
*/
|
||||
JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0;
|
||||
JDIMENSION delta = (cinfo->Ss == 0) ? 2 : 0;
|
||||
if (cinfo->input_iMCU_row > cinfo->output_iMCU_row + delta)
|
||||
break;
|
||||
}
|
||||
@@ -452,34 +475,53 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
if (!compptr->component_needed)
|
||||
continue;
|
||||
/* Count non-dummy DCT block rows in this iMCU row. */
|
||||
if (cinfo->output_iMCU_row < last_iMCU_row) {
|
||||
if (cinfo->output_iMCU_row < last_iMCU_row - 1) {
|
||||
block_rows = compptr->v_samp_factor;
|
||||
access_rows = block_rows * 3; /* this and next two iMCU rows */
|
||||
} else if (cinfo->output_iMCU_row < last_iMCU_row) {
|
||||
block_rows = compptr->v_samp_factor;
|
||||
access_rows = block_rows * 2; /* this and next iMCU row */
|
||||
last_row = FALSE;
|
||||
} else {
|
||||
/* NB: can't use last_row_height here; it is input-side-dependent! */
|
||||
block_rows = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
|
||||
if (block_rows == 0) block_rows = compptr->v_samp_factor;
|
||||
access_rows = block_rows; /* this iMCU row only */
|
||||
last_row = TRUE;
|
||||
}
|
||||
/* Align the virtual buffer for this component. */
|
||||
if (cinfo->output_iMCU_row > 0) {
|
||||
access_rows += compptr->v_samp_factor; /* prior iMCU row too */
|
||||
if (cinfo->output_iMCU_row > 1) {
|
||||
access_rows += 2 * compptr->v_samp_factor; /* prior two iMCU rows too */
|
||||
buffer = (*cinfo->mem->access_virt_barray)
|
||||
((j_common_ptr)cinfo, coef->whole_image[ci],
|
||||
(cinfo->output_iMCU_row - 2) * compptr->v_samp_factor,
|
||||
(JDIMENSION)access_rows, FALSE);
|
||||
buffer += 2 * compptr->v_samp_factor; /* point to current iMCU row */
|
||||
} else if (cinfo->output_iMCU_row > 0) {
|
||||
buffer = (*cinfo->mem->access_virt_barray)
|
||||
((j_common_ptr)cinfo, coef->whole_image[ci],
|
||||
(cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,
|
||||
(JDIMENSION)access_rows, FALSE);
|
||||
buffer += compptr->v_samp_factor; /* point to current iMCU row */
|
||||
first_row = FALSE;
|
||||
} else {
|
||||
buffer = (*cinfo->mem->access_virt_barray)
|
||||
((j_common_ptr)cinfo, coef->whole_image[ci],
|
||||
(JDIMENSION)0, (JDIMENSION)access_rows, FALSE);
|
||||
first_row = TRUE;
|
||||
}
|
||||
/* Fetch component-dependent info */
|
||||
coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS);
|
||||
/* Fetch component-dependent info.
|
||||
* If the current scan is incomplete, then we use the component-dependent
|
||||
* info from the previous scan.
|
||||
*/
|
||||
if (cinfo->output_iMCU_row > cinfo->master->last_good_iMCU_row)
|
||||
coef_bits =
|
||||
coef->coef_bits_latch + ((ci + cinfo->num_components) * SAVED_COEFS);
|
||||
else
|
||||
coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS);
|
||||
|
||||
/* We only do DC interpolation if no AC coefficient data is available. */
|
||||
change_dc =
|
||||
coef_bits[1] == -1 && coef_bits[2] == -1 && coef_bits[3] == -1 &&
|
||||
coef_bits[4] == -1 && coef_bits[5] == -1 && coef_bits[6] == -1 &&
|
||||
coef_bits[7] == -1 && coef_bits[8] == -1 && coef_bits[9] == -1;
|
||||
|
||||
quanttbl = compptr->quant_table;
|
||||
Q00 = quanttbl->quantval[0];
|
||||
Q01 = quanttbl->quantval[Q01_POS];
|
||||
@@ -487,27 +529,51 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
Q20 = quanttbl->quantval[Q20_POS];
|
||||
Q11 = quanttbl->quantval[Q11_POS];
|
||||
Q02 = quanttbl->quantval[Q02_POS];
|
||||
if (change_dc) {
|
||||
Q03 = quanttbl->quantval[Q03_POS];
|
||||
Q12 = quanttbl->quantval[Q12_POS];
|
||||
Q21 = quanttbl->quantval[Q21_POS];
|
||||
Q30 = quanttbl->quantval[Q30_POS];
|
||||
}
|
||||
inverse_DCT = cinfo->idct->inverse_DCT[ci];
|
||||
output_ptr = output_buf[ci];
|
||||
/* Loop over all DCT blocks to be processed. */
|
||||
for (block_row = 0; block_row < block_rows; block_row++) {
|
||||
buffer_ptr = buffer[block_row] + cinfo->master->first_MCU_col[ci];
|
||||
if (first_row && block_row == 0)
|
||||
|
||||
if (block_row > 0 || cinfo->output_iMCU_row > 0)
|
||||
prev_block_row =
|
||||
buffer[block_row - 1] + cinfo->master->first_MCU_col[ci];
|
||||
else
|
||||
prev_block_row = buffer_ptr;
|
||||
|
||||
if (block_row > 1 || cinfo->output_iMCU_row > 1)
|
||||
prev_prev_block_row =
|
||||
buffer[block_row - 2] + cinfo->master->first_MCU_col[ci];
|
||||
else
|
||||
prev_prev_block_row = prev_block_row;
|
||||
|
||||
if (block_row < block_rows - 1 || cinfo->output_iMCU_row < last_iMCU_row)
|
||||
next_block_row =
|
||||
buffer[block_row + 1] + cinfo->master->first_MCU_col[ci];
|
||||
else
|
||||
prev_block_row = buffer[block_row - 1] +
|
||||
cinfo->master->first_MCU_col[ci];
|
||||
if (last_row && block_row == block_rows - 1)
|
||||
next_block_row = buffer_ptr;
|
||||
|
||||
if (block_row < block_rows - 2 ||
|
||||
cinfo->output_iMCU_row < last_iMCU_row - 1)
|
||||
next_next_block_row =
|
||||
buffer[block_row + 2] + cinfo->master->first_MCU_col[ci];
|
||||
else
|
||||
next_block_row = buffer[block_row + 1] +
|
||||
cinfo->master->first_MCU_col[ci];
|
||||
next_next_block_row = next_block_row;
|
||||
|
||||
/* We fetch the surrounding DC values using a sliding-register approach.
|
||||
* Initialize all nine here so as to do the right thing on narrow pics.
|
||||
* Initialize all 25 here so as to do the right thing on narrow pics.
|
||||
*/
|
||||
DC1 = DC2 = DC3 = (int)prev_block_row[0][0];
|
||||
DC4 = DC5 = DC6 = (int)buffer_ptr[0][0];
|
||||
DC7 = DC8 = DC9 = (int)next_block_row[0][0];
|
||||
DC01 = DC02 = DC03 = DC04 = DC05 = (int)prev_prev_block_row[0][0];
|
||||
DC06 = DC07 = DC08 = DC09 = DC10 = (int)prev_block_row[0][0];
|
||||
DC11 = DC12 = DC13 = DC14 = DC15 = (int)buffer_ptr[0][0];
|
||||
DC16 = DC17 = DC18 = DC19 = DC20 = (int)next_block_row[0][0];
|
||||
DC21 = DC22 = DC23 = DC24 = DC25 = (int)next_next_block_row[0][0];
|
||||
output_col = 0;
|
||||
last_block_column = compptr->width_in_blocks - 1;
|
||||
for (block_num = cinfo->master->first_MCU_col[ci];
|
||||
@@ -515,18 +581,39 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
/* Fetch current DCT block into workspace so we can modify it. */
|
||||
jcopy_block_row(buffer_ptr, (JBLOCKROW)workspace, (JDIMENSION)1);
|
||||
/* Update DC values */
|
||||
if (block_num < last_block_column) {
|
||||
DC3 = (int)prev_block_row[1][0];
|
||||
DC6 = (int)buffer_ptr[1][0];
|
||||
DC9 = (int)next_block_row[1][0];
|
||||
if (block_num == cinfo->master->first_MCU_col[ci] &&
|
||||
block_num < last_block_column) {
|
||||
DC04 = (int)prev_prev_block_row[1][0];
|
||||
DC09 = (int)prev_block_row[1][0];
|
||||
DC14 = (int)buffer_ptr[1][0];
|
||||
DC19 = (int)next_block_row[1][0];
|
||||
DC24 = (int)next_next_block_row[1][0];
|
||||
}
|
||||
/* Compute coefficient estimates per K.8.
|
||||
* An estimate is applied only if coefficient is still zero,
|
||||
* and is not known to be fully accurate.
|
||||
if (block_num + 1 < last_block_column) {
|
||||
DC05 = (int)prev_prev_block_row[2][0];
|
||||
DC10 = (int)prev_block_row[2][0];
|
||||
DC15 = (int)buffer_ptr[2][0];
|
||||
DC20 = (int)next_block_row[2][0];
|
||||
DC25 = (int)next_next_block_row[2][0];
|
||||
}
|
||||
/* If DC interpolation is enabled, compute coefficient estimates using
|
||||
* a Gaussian-like kernel, keeping the averages of the DC values.
|
||||
*
|
||||
* If DC interpolation is disabled, compute coefficient estimates using
|
||||
* an algorithm similar to the one described in Section K.8 of the JPEG
|
||||
* standard, except applied to a 5x5 window rather than a 3x3 window.
|
||||
*
|
||||
* An estimate is applied only if the coefficient is still zero and is
|
||||
* not known to be fully accurate.
|
||||
*/
|
||||
/* AC01 */
|
||||
if ((Al = coef_bits[1]) != 0 && workspace[1] == 0) {
|
||||
num = 36 * Q00 * (DC4 - DC6);
|
||||
num = Q00 * (change_dc ?
|
||||
(-DC01 - DC02 + DC04 + DC05 - 3 * DC06 + 13 * DC07 -
|
||||
13 * DC09 + 3 * DC10 - 3 * DC11 + 38 * DC12 - 38 * DC14 +
|
||||
3 * DC15 - 3 * DC16 + 13 * DC17 - 13 * DC19 + 3 * DC20 -
|
||||
DC21 - DC22 + DC24 + DC25) :
|
||||
(-7 * DC11 + 50 * DC12 - 50 * DC14 + 7 * DC15));
|
||||
if (num >= 0) {
|
||||
pred = (int)(((Q01 << 7) + num) / (Q01 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
@@ -541,7 +628,12 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
}
|
||||
/* AC10 */
|
||||
if ((Al = coef_bits[2]) != 0 && workspace[8] == 0) {
|
||||
num = 36 * Q00 * (DC2 - DC8);
|
||||
num = Q00 * (change_dc ?
|
||||
(-DC01 - 3 * DC02 - 3 * DC03 - 3 * DC04 - DC05 - DC06 +
|
||||
13 * DC07 + 38 * DC08 + 13 * DC09 - DC10 + DC16 -
|
||||
13 * DC17 - 38 * DC18 - 13 * DC19 + DC20 + DC21 +
|
||||
3 * DC22 + 3 * DC23 + 3 * DC24 + DC25) :
|
||||
(-7 * DC03 + 50 * DC08 - 50 * DC18 + 7 * DC23));
|
||||
if (num >= 0) {
|
||||
pred = (int)(((Q10 << 7) + num) / (Q10 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
@@ -556,7 +648,10 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
}
|
||||
/* AC20 */
|
||||
if ((Al = coef_bits[3]) != 0 && workspace[16] == 0) {
|
||||
num = 9 * Q00 * (DC2 + DC8 - 2 * DC5);
|
||||
num = Q00 * (change_dc ?
|
||||
(DC03 + 2 * DC07 + 7 * DC08 + 2 * DC09 - 5 * DC12 - 14 * DC13 -
|
||||
5 * DC14 + 2 * DC17 + 7 * DC18 + 2 * DC19 + DC23) :
|
||||
(-DC03 + 13 * DC08 - 24 * DC13 + 13 * DC18 - DC23));
|
||||
if (num >= 0) {
|
||||
pred = (int)(((Q20 << 7) + num) / (Q20 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
@@ -571,7 +666,11 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
}
|
||||
/* AC11 */
|
||||
if ((Al = coef_bits[4]) != 0 && workspace[9] == 0) {
|
||||
num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9);
|
||||
num = Q00 * (change_dc ?
|
||||
(-DC01 + DC05 + 9 * DC07 - 9 * DC09 - 9 * DC17 +
|
||||
9 * DC19 + DC21 - DC25) :
|
||||
(DC10 + DC16 - 10 * DC17 + 10 * DC19 - DC02 - DC20 + DC22 -
|
||||
DC24 + DC04 - DC06 + 10 * DC07 - 10 * DC09));
|
||||
if (num >= 0) {
|
||||
pred = (int)(((Q11 << 7) + num) / (Q11 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
@@ -586,7 +685,10 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
}
|
||||
/* AC02 */
|
||||
if ((Al = coef_bits[5]) != 0 && workspace[2] == 0) {
|
||||
num = 9 * Q00 * (DC4 + DC6 - 2 * DC5);
|
||||
num = Q00 * (change_dc ?
|
||||
(2 * DC07 - 5 * DC08 + 2 * DC09 + DC11 + 7 * DC12 - 14 * DC13 +
|
||||
7 * DC14 + DC15 + 2 * DC17 - 5 * DC18 + 2 * DC19) :
|
||||
(-DC11 + 13 * DC12 - 24 * DC13 + 13 * DC14 - DC15));
|
||||
if (num >= 0) {
|
||||
pred = (int)(((Q02 << 7) + num) / (Q02 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
@@ -599,14 +701,96 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
|
||||
}
|
||||
workspace[2] = (JCOEF)pred;
|
||||
}
|
||||
if (change_dc) {
|
||||
/* AC03 */
|
||||
if ((Al = coef_bits[6]) != 0 && workspace[3] == 0) {
|
||||
num = Q00 * (DC07 - DC09 + 2 * DC12 - 2 * DC14 + DC17 - DC19);
|
||||
if (num >= 0) {
|
||||
pred = (int)(((Q03 << 7) + num) / (Q03 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
pred = (1 << Al) - 1;
|
||||
} else {
|
||||
pred = (int)(((Q03 << 7) - num) / (Q03 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
pred = (1 << Al) - 1;
|
||||
pred = -pred;
|
||||
}
|
||||
workspace[3] = (JCOEF)pred;
|
||||
}
|
||||
/* AC12 */
|
||||
if ((Al = coef_bits[7]) != 0 && workspace[10] == 0) {
|
||||
num = Q00 * (DC07 - 3 * DC08 + DC09 - DC17 + 3 * DC18 - DC19);
|
||||
if (num >= 0) {
|
||||
pred = (int)(((Q12 << 7) + num) / (Q12 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
pred = (1 << Al) - 1;
|
||||
} else {
|
||||
pred = (int)(((Q12 << 7) - num) / (Q12 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
pred = (1 << Al) - 1;
|
||||
pred = -pred;
|
||||
}
|
||||
workspace[10] = (JCOEF)pred;
|
||||
}
|
||||
/* AC21 */
|
||||
if ((Al = coef_bits[8]) != 0 && workspace[17] == 0) {
|
||||
num = Q00 * (DC07 - DC09 - 3 * DC12 + 3 * DC14 + DC17 - DC19);
|
||||
if (num >= 0) {
|
||||
pred = (int)(((Q21 << 7) + num) / (Q21 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
pred = (1 << Al) - 1;
|
||||
} else {
|
||||
pred = (int)(((Q21 << 7) - num) / (Q21 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
pred = (1 << Al) - 1;
|
||||
pred = -pred;
|
||||
}
|
||||
workspace[17] = (JCOEF)pred;
|
||||
}
|
||||
/* AC30 */
|
||||
if ((Al = coef_bits[9]) != 0 && workspace[24] == 0) {
|
||||
num = Q00 * (DC07 + 2 * DC08 + DC09 - DC17 - 2 * DC18 - DC19);
|
||||
if (num >= 0) {
|
||||
pred = (int)(((Q30 << 7) + num) / (Q30 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
pred = (1 << Al) - 1;
|
||||
} else {
|
||||
pred = (int)(((Q30 << 7) - num) / (Q30 << 8));
|
||||
if (Al > 0 && pred >= (1 << Al))
|
||||
pred = (1 << Al) - 1;
|
||||
pred = -pred;
|
||||
}
|
||||
workspace[24] = (JCOEF)pred;
|
||||
}
|
||||
/* coef_bits[0] is non-negative. Otherwise this function would not
|
||||
* be called.
|
||||
*/
|
||||
num = Q00 *
|
||||
(-2 * DC01 - 6 * DC02 - 8 * DC03 - 6 * DC04 - 2 * DC05 -
|
||||
6 * DC06 + 6 * DC07 + 42 * DC08 + 6 * DC09 - 6 * DC10 -
|
||||
8 * DC11 + 42 * DC12 + 152 * DC13 + 42 * DC14 - 8 * DC15 -
|
||||
6 * DC16 + 6 * DC17 + 42 * DC18 + 6 * DC19 - 6 * DC20 -
|
||||
2 * DC21 - 6 * DC22 - 8 * DC23 - 6 * DC24 - 2 * DC25);
|
||||
if (num >= 0) {
|
||||
pred = (int)(((Q00 << 7) + num) / (Q00 << 8));
|
||||
} else {
|
||||
pred = (int)(((Q00 << 7) - num) / (Q00 << 8));
|
||||
pred = -pred;
|
||||
}
|
||||
workspace[0] = (JCOEF)pred;
|
||||
} /* change_dc */
|
||||
|
||||
/* OK, do the IDCT */
|
||||
(*inverse_DCT) (cinfo, compptr, (JCOEFPTR)workspace, output_ptr,
|
||||
output_col);
|
||||
/* Advance for next column */
|
||||
DC1 = DC2; DC2 = DC3;
|
||||
DC4 = DC5; DC5 = DC6;
|
||||
DC7 = DC8; DC8 = DC9;
|
||||
buffer_ptr++, prev_block_row++, next_block_row++;
|
||||
DC01 = DC02; DC02 = DC03; DC03 = DC04; DC04 = DC05;
|
||||
DC06 = DC07; DC07 = DC08; DC08 = DC09; DC09 = DC10;
|
||||
DC11 = DC12; DC12 = DC13; DC13 = DC14; DC14 = DC15;
|
||||
DC16 = DC17; DC17 = DC18; DC18 = DC19; DC19 = DC20;
|
||||
DC21 = DC22; DC22 = DC23; DC23 = DC24; DC24 = DC25;
|
||||
buffer_ptr++, prev_block_row++, next_block_row++,
|
||||
prev_prev_block_row++, next_next_block_row++;
|
||||
output_col += compptr->_DCT_scaled_size;
|
||||
}
|
||||
output_ptr += compptr->_DCT_scaled_size;
|
||||
@@ -655,7 +839,7 @@ jinit_d_coef_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
|
||||
#ifdef BLOCK_SMOOTHING_SUPPORTED
|
||||
/* If block smoothing could be used, need a bigger window */
|
||||
if (cinfo->progressive_mode)
|
||||
access_rows *= 3;
|
||||
access_rows *= 5;
|
||||
#endif
|
||||
coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
|
||||
((j_common_ptr)cinfo, JPOOL_IMAGE, TRUE,
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@
|
||||
* Copyright (C) 1994-1997, Thomas G. Lane.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||
* Copyright (C) 2020, Google, Inc.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*/
|
||||
@@ -51,7 +52,7 @@ typedef struct {
|
||||
#ifdef BLOCK_SMOOTHING_SUPPORTED
|
||||
/* When doing block smoothing, we latch coefficient Al values here */
|
||||
int *coef_bits_latch;
|
||||
#define SAVED_COEFS 6 /* we save coef_bits[0..5] */
|
||||
#define SAVED_COEFS 10 /* we save coef_bits[0..9] */
|
||||
#endif
|
||||
} my_coef_controller;
|
||||
|
||||
|
||||
+48
-48
@@ -45,9 +45,9 @@ ycc_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
outptr = *output_buf++;
|
||||
|
||||
if (PACK_NEED_ALIGNMENT(outptr)) {
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
y = *inptr0++;
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
r = range_limit[y + Crrtab[cr]];
|
||||
g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
|
||||
SCALEBITS))];
|
||||
@@ -58,18 +58,18 @@ ycc_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
num_cols--;
|
||||
}
|
||||
for (col = 0; col < (num_cols >> 1); col++) {
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
y = *inptr0++;
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
r = range_limit[y + Crrtab[cr]];
|
||||
g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
|
||||
SCALEBITS))];
|
||||
b = range_limit[y + Cbbtab[cb]];
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
y = *inptr0++;
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
r = range_limit[y + Crrtab[cr]];
|
||||
g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
|
||||
SCALEBITS))];
|
||||
@@ -80,9 +80,9 @@ ycc_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
outptr += 4;
|
||||
}
|
||||
if (num_cols & 1) {
|
||||
y = GETJSAMPLE(*inptr0);
|
||||
cb = GETJSAMPLE(*inptr1);
|
||||
cr = GETJSAMPLE(*inptr2);
|
||||
y = *inptr0;
|
||||
cb = *inptr1;
|
||||
cr = *inptr2;
|
||||
r = range_limit[y + Crrtab[cr]];
|
||||
g = range_limit[y + ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
|
||||
SCALEBITS))];
|
||||
@@ -125,9 +125,9 @@ ycc_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
input_row++;
|
||||
outptr = *output_buf++;
|
||||
if (PACK_NEED_ALIGNMENT(outptr)) {
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
y = *inptr0++;
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)];
|
||||
g = range_limit[DITHER_565_G(y +
|
||||
((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
|
||||
@@ -139,9 +139,9 @@ ycc_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
num_cols--;
|
||||
}
|
||||
for (col = 0; col < (num_cols >> 1); col++) {
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
y = *inptr0++;
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)];
|
||||
g = range_limit[DITHER_565_G(y +
|
||||
((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
|
||||
@@ -150,9 +150,9 @@ ycc_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
d0 = DITHER_ROTATE(d0);
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
y = *inptr0++;
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)];
|
||||
g = range_limit[DITHER_565_G(y +
|
||||
((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
|
||||
@@ -165,9 +165,9 @@ ycc_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
outptr += 4;
|
||||
}
|
||||
if (num_cols & 1) {
|
||||
y = GETJSAMPLE(*inptr0);
|
||||
cb = GETJSAMPLE(*inptr1);
|
||||
cr = GETJSAMPLE(*inptr2);
|
||||
y = *inptr0;
|
||||
cb = *inptr1;
|
||||
cr = *inptr2;
|
||||
r = range_limit[DITHER_565_R(y + Crrtab[cr], d0)];
|
||||
g = range_limit[DITHER_565_G(y +
|
||||
((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
|
||||
@@ -202,32 +202,32 @@ rgb_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
input_row++;
|
||||
outptr = *output_buf++;
|
||||
if (PACK_NEED_ALIGNMENT(outptr)) {
|
||||
r = GETJSAMPLE(*inptr0++);
|
||||
g = GETJSAMPLE(*inptr1++);
|
||||
b = GETJSAMPLE(*inptr2++);
|
||||
r = *inptr0++;
|
||||
g = *inptr1++;
|
||||
b = *inptr2++;
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
*(INT16 *)outptr = (INT16)rgb;
|
||||
outptr += 2;
|
||||
num_cols--;
|
||||
}
|
||||
for (col = 0; col < (num_cols >> 1); col++) {
|
||||
r = GETJSAMPLE(*inptr0++);
|
||||
g = GETJSAMPLE(*inptr1++);
|
||||
b = GETJSAMPLE(*inptr2++);
|
||||
r = *inptr0++;
|
||||
g = *inptr1++;
|
||||
b = *inptr2++;
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
|
||||
r = GETJSAMPLE(*inptr0++);
|
||||
g = GETJSAMPLE(*inptr1++);
|
||||
b = GETJSAMPLE(*inptr2++);
|
||||
r = *inptr0++;
|
||||
g = *inptr1++;
|
||||
b = *inptr2++;
|
||||
rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b));
|
||||
|
||||
WRITE_TWO_ALIGNED_PIXELS(outptr, rgb);
|
||||
outptr += 4;
|
||||
}
|
||||
if (num_cols & 1) {
|
||||
r = GETJSAMPLE(*inptr0);
|
||||
g = GETJSAMPLE(*inptr1);
|
||||
b = GETJSAMPLE(*inptr2);
|
||||
r = *inptr0;
|
||||
g = *inptr1;
|
||||
b = *inptr2;
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
*(INT16 *)outptr = (INT16)rgb;
|
||||
}
|
||||
@@ -259,24 +259,24 @@ rgb_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
input_row++;
|
||||
outptr = *output_buf++;
|
||||
if (PACK_NEED_ALIGNMENT(outptr)) {
|
||||
r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0++), d0)];
|
||||
g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)];
|
||||
b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)];
|
||||
r = range_limit[DITHER_565_R(*inptr0++, d0)];
|
||||
g = range_limit[DITHER_565_G(*inptr1++, d0)];
|
||||
b = range_limit[DITHER_565_B(*inptr2++, d0)];
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
*(INT16 *)outptr = (INT16)rgb;
|
||||
outptr += 2;
|
||||
num_cols--;
|
||||
}
|
||||
for (col = 0; col < (num_cols >> 1); col++) {
|
||||
r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0++), d0)];
|
||||
g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)];
|
||||
b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)];
|
||||
r = range_limit[DITHER_565_R(*inptr0++, d0)];
|
||||
g = range_limit[DITHER_565_G(*inptr1++, d0)];
|
||||
b = range_limit[DITHER_565_B(*inptr2++, d0)];
|
||||
d0 = DITHER_ROTATE(d0);
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
|
||||
r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0++), d0)];
|
||||
g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)];
|
||||
b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)];
|
||||
r = range_limit[DITHER_565_R(*inptr0++, d0)];
|
||||
g = range_limit[DITHER_565_G(*inptr1++, d0)];
|
||||
b = range_limit[DITHER_565_B(*inptr2++, d0)];
|
||||
d0 = DITHER_ROTATE(d0);
|
||||
rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r, g, b));
|
||||
|
||||
@@ -284,9 +284,9 @@ rgb_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
outptr += 4;
|
||||
}
|
||||
if (num_cols & 1) {
|
||||
r = range_limit[DITHER_565_R(GETJSAMPLE(*inptr0), d0)];
|
||||
g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1), d0)];
|
||||
b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2), d0)];
|
||||
r = range_limit[DITHER_565_R(*inptr0, d0)];
|
||||
g = range_limit[DITHER_565_G(*inptr1, d0)];
|
||||
b = range_limit[DITHER_565_B(*inptr2, d0)];
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
*(INT16 *)outptr = (INT16)rgb;
|
||||
}
|
||||
|
||||
+3
-5
@@ -53,9 +53,9 @@ ycc_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
input_row++;
|
||||
outptr = *output_buf++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
y = GETJSAMPLE(inptr0[col]);
|
||||
cb = GETJSAMPLE(inptr1[col]);
|
||||
cr = GETJSAMPLE(inptr2[col]);
|
||||
y = inptr0[col];
|
||||
cb = inptr1[col];
|
||||
cr = inptr2[col];
|
||||
/* Range-limiting is essential due to noise introduced by DCT losses. */
|
||||
outptr[RGB_RED] = range_limit[y + Crrtab[cr]];
|
||||
outptr[RGB_GREEN] = range_limit[y +
|
||||
@@ -93,7 +93,6 @@ gray_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
inptr = input_buf[0][input_row++];
|
||||
outptr = *output_buf++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
/* We can dispense with GETJSAMPLE() here */
|
||||
outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];
|
||||
/* Set unused byte to 0xFF so it can be interpreted as an opaque */
|
||||
/* alpha channel value */
|
||||
@@ -128,7 +127,6 @@ rgb_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
input_row++;
|
||||
outptr = *output_buf++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
/* We can dispense with GETJSAMPLE() here */
|
||||
outptr[RGB_RED] = inptr0[col];
|
||||
outptr[RGB_GREEN] = inptr1[col];
|
||||
outptr[RGB_BLUE] = inptr2[col];
|
||||
|
||||
Vendored
+7
-7
@@ -341,9 +341,9 @@ rgb_gray_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
input_row++;
|
||||
outptr = *output_buf++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
r = GETJSAMPLE(inptr0[col]);
|
||||
g = GETJSAMPLE(inptr1[col]);
|
||||
b = GETJSAMPLE(inptr2[col]);
|
||||
r = inptr0[col];
|
||||
g = inptr1[col];
|
||||
b = inptr2[col];
|
||||
/* Y */
|
||||
outptr[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
|
||||
ctab[b + B_Y_OFF]) >> SCALEBITS);
|
||||
@@ -550,9 +550,9 @@ ycck_cmyk_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
input_row++;
|
||||
outptr = *output_buf++;
|
||||
for (col = 0; col < num_cols; col++) {
|
||||
y = GETJSAMPLE(inptr0[col]);
|
||||
cb = GETJSAMPLE(inptr1[col]);
|
||||
cr = GETJSAMPLE(inptr2[col]);
|
||||
y = inptr0[col];
|
||||
cb = inptr1[col];
|
||||
cr = inptr2[col];
|
||||
/* Range-limiting is essential due to noise introduced by DCT losses. */
|
||||
outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */
|
||||
outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */
|
||||
@@ -560,7 +560,7 @@ ycck_cmyk_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
SCALEBITS)))];
|
||||
outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */
|
||||
/* K passes through unchanged */
|
||||
outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */
|
||||
outptr[3] = inptr3[col];
|
||||
outptr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+27
-33
@@ -5,6 +5,7 @@
|
||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2009-2011, 2016, 2018-2019, D. R. Commander.
|
||||
* Copyright (C) 2018, Matthias Räncker.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -39,24 +40,6 @@ typedef struct {
|
||||
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
|
||||
} savable_state;
|
||||
|
||||
/* This macro is to work around compilers with missing or broken
|
||||
* structure assignment. You'll need to fix this code if you have
|
||||
* such a compiler and you change MAX_COMPS_IN_SCAN.
|
||||
*/
|
||||
|
||||
#ifndef NO_STRUCT_ASSIGN
|
||||
#define ASSIGN_STATE(dest, src) ((dest) = (src))
|
||||
#else
|
||||
#if MAX_COMPS_IN_SCAN == 4
|
||||
#define ASSIGN_STATE(dest, src) \
|
||||
((dest).last_dc_val[0] = (src).last_dc_val[0], \
|
||||
(dest).last_dc_val[1] = (src).last_dc_val[1], \
|
||||
(dest).last_dc_val[2] = (src).last_dc_val[2], \
|
||||
(dest).last_dc_val[3] = (src).last_dc_val[3])
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct jpeg_entropy_decoder pub; /* public fields */
|
||||
|
||||
@@ -325,7 +308,7 @@ jpeg_fill_bit_buffer(bitread_working_state *state,
|
||||
bytes_in_buffer = cinfo->src->bytes_in_buffer;
|
||||
}
|
||||
bytes_in_buffer--;
|
||||
c = GETJOCTET(*next_input_byte++);
|
||||
c = *next_input_byte++;
|
||||
|
||||
/* If it's 0xFF, check and discard stuffed zero byte */
|
||||
if (c == 0xFF) {
|
||||
@@ -342,7 +325,7 @@ jpeg_fill_bit_buffer(bitread_working_state *state,
|
||||
bytes_in_buffer = cinfo->src->bytes_in_buffer;
|
||||
}
|
||||
bytes_in_buffer--;
|
||||
c = GETJOCTET(*next_input_byte++);
|
||||
c = *next_input_byte++;
|
||||
} while (c == 0xFF);
|
||||
|
||||
if (c == 0) {
|
||||
@@ -405,8 +388,8 @@ no_more_bytes:
|
||||
|
||||
#define GET_BYTE { \
|
||||
register int c0, c1; \
|
||||
c0 = GETJOCTET(*buffer++); \
|
||||
c1 = GETJOCTET(*buffer); \
|
||||
c0 = *buffer++; \
|
||||
c1 = *buffer; \
|
||||
/* Pre-execute most common case */ \
|
||||
get_buffer = (get_buffer << 8) | c0; \
|
||||
bits_left += 8; \
|
||||
@@ -423,7 +406,7 @@ no_more_bytes:
|
||||
} \
|
||||
}
|
||||
|
||||
#if SIZEOF_SIZE_T == 8 || defined(_WIN64)
|
||||
#if SIZEOF_SIZE_T == 8 || defined(_WIN64) || (defined(__x86_64__) && defined(__ILP32__))
|
||||
|
||||
/* Pre-fetch 48 bytes, because the holding register is 64-bit */
|
||||
#define FILL_BIT_BUFFER_FAST \
|
||||
@@ -557,6 +540,12 @@ process_restart(j_decompress_ptr cinfo)
|
||||
}
|
||||
|
||||
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(undefined_behavior_sanitizer)
|
||||
__attribute__((no_sanitize("signed-integer-overflow"),
|
||||
no_sanitize("unsigned-integer-overflow")))
|
||||
#endif
|
||||
#endif
|
||||
LOCAL(boolean)
|
||||
decode_mcu_slow(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
{
|
||||
@@ -568,7 +557,7 @@ decode_mcu_slow(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
|
||||
/* Load up working state */
|
||||
BITREAD_LOAD_STATE(cinfo, entropy->bitstate);
|
||||
ASSIGN_STATE(state, entropy->saved);
|
||||
state = entropy->saved;
|
||||
|
||||
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
||||
JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL;
|
||||
@@ -589,11 +578,15 @@ decode_mcu_slow(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
if (entropy->dc_needed[blkn]) {
|
||||
/* Convert DC difference to actual value, update last_dc_val */
|
||||
int ci = cinfo->MCU_membership[blkn];
|
||||
/* This is really just
|
||||
* s += state.last_dc_val[ci];
|
||||
* It is written this way in order to shut up UBSan.
|
||||
/* Certain malformed JPEG images produce repeated DC coefficient
|
||||
* differences of 2047 or -2047, which causes state.last_dc_val[ci] to
|
||||
* grow until it overflows or underflows a 32-bit signed integer. This
|
||||
* behavior is, to the best of our understanding, innocuous, and it is
|
||||
* unclear how to work around it without potentially affecting
|
||||
* performance. Thus, we (hopefully temporarily) suppress UBSan integer
|
||||
* overflow errors for this function.
|
||||
*/
|
||||
s = (int)((unsigned int)s + (unsigned int)state.last_dc_val[ci]);
|
||||
s += state.last_dc_val[ci];
|
||||
state.last_dc_val[ci] = s;
|
||||
if (block) {
|
||||
/* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
|
||||
@@ -653,7 +646,7 @@ decode_mcu_slow(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
|
||||
/* Completed MCU, so update state */
|
||||
BITREAD_SAVE_STATE(cinfo, entropy->bitstate);
|
||||
ASSIGN_STATE(entropy->saved, state);
|
||||
entropy->saved = state;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -671,7 +664,7 @@ decode_mcu_fast(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
/* Load up working state */
|
||||
BITREAD_LOAD_STATE(cinfo, entropy->bitstate);
|
||||
buffer = (JOCTET *)br_state.next_input_byte;
|
||||
ASSIGN_STATE(state, entropy->saved);
|
||||
state = entropy->saved;
|
||||
|
||||
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
|
||||
JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL;
|
||||
@@ -688,7 +681,7 @@ decode_mcu_fast(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
|
||||
if (entropy->dc_needed[blkn]) {
|
||||
int ci = cinfo->MCU_membership[blkn];
|
||||
s = (int)((unsigned int)s + (unsigned int)state.last_dc_val[ci]);
|
||||
s += state.last_dc_val[ci];
|
||||
state.last_dc_val[ci] = s;
|
||||
if (block)
|
||||
(*block)[0] = (JCOEF)s;
|
||||
@@ -740,7 +733,7 @@ decode_mcu_fast(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
br_state.bytes_in_buffer -= (buffer - br_state.next_input_byte);
|
||||
br_state.next_input_byte = buffer;
|
||||
BITREAD_SAVE_STATE(cinfo, entropy->bitstate);
|
||||
ASSIGN_STATE(entropy->saved, state);
|
||||
entropy->saved = state;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -795,7 +788,8 @@ use_slow:
|
||||
}
|
||||
|
||||
/* Account for restart interval (no-op if not using restarts) */
|
||||
entropy->restarts_to_go--;
|
||||
if (cinfo->restart_interval)
|
||||
entropy->restarts_to_go--;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Vendored
+11
-2
@@ -4,7 +4,8 @@
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2010-2011, 2015-2016, D. R. Commander.
|
||||
* Copyright (C) 2010-2011, 2015-2016, 2021, D. R. Commander.
|
||||
* Copyright (C) 2018, Matthias Räncker.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -78,6 +79,11 @@ EXTERN(void) jpeg_make_d_derived_tbl(j_decompress_ptr cinfo, boolean isDC,
|
||||
typedef size_t bit_buf_type; /* type of bit-extraction buffer */
|
||||
#define BIT_BUF_SIZE 64 /* size of buffer in bits */
|
||||
|
||||
#elif defined(__x86_64__) && defined(__ILP32__)
|
||||
|
||||
typedef unsigned long long bit_buf_type; /* type of bit-extraction buffer */
|
||||
#define BIT_BUF_SIZE 64 /* size of buffer in bits */
|
||||
|
||||
#else
|
||||
|
||||
typedef unsigned long bit_buf_type; /* type of bit-extraction buffer */
|
||||
@@ -228,7 +234,10 @@ slowlabel: \
|
||||
s |= GET_BITS(1); \
|
||||
nb++; \
|
||||
} \
|
||||
s = htbl->pub->huffval[(int)(s + htbl->valoffset[nb]) & 0xFF]; \
|
||||
if (nb > 16) \
|
||||
s = 0; \
|
||||
else \
|
||||
s = htbl->pub->huffval[(int)(s + htbl->valoffset[nb]) & 0xFF]; \
|
||||
}
|
||||
|
||||
/* Out-of-line case for Huffman code fetching */
|
||||
|
||||
Vendored
+16
-16
@@ -38,18 +38,18 @@ marker_is_icc(jpeg_saved_marker_ptr marker)
|
||||
marker->marker == ICC_MARKER &&
|
||||
marker->data_length >= ICC_OVERHEAD_LEN &&
|
||||
/* verify the identifying string */
|
||||
GETJOCTET(marker->data[0]) == 0x49 &&
|
||||
GETJOCTET(marker->data[1]) == 0x43 &&
|
||||
GETJOCTET(marker->data[2]) == 0x43 &&
|
||||
GETJOCTET(marker->data[3]) == 0x5F &&
|
||||
GETJOCTET(marker->data[4]) == 0x50 &&
|
||||
GETJOCTET(marker->data[5]) == 0x52 &&
|
||||
GETJOCTET(marker->data[6]) == 0x4F &&
|
||||
GETJOCTET(marker->data[7]) == 0x46 &&
|
||||
GETJOCTET(marker->data[8]) == 0x49 &&
|
||||
GETJOCTET(marker->data[9]) == 0x4C &&
|
||||
GETJOCTET(marker->data[10]) == 0x45 &&
|
||||
GETJOCTET(marker->data[11]) == 0x0;
|
||||
marker->data[0] == 0x49 &&
|
||||
marker->data[1] == 0x43 &&
|
||||
marker->data[2] == 0x43 &&
|
||||
marker->data[3] == 0x5F &&
|
||||
marker->data[4] == 0x50 &&
|
||||
marker->data[5] == 0x52 &&
|
||||
marker->data[6] == 0x4F &&
|
||||
marker->data[7] == 0x46 &&
|
||||
marker->data[8] == 0x49 &&
|
||||
marker->data[9] == 0x4C &&
|
||||
marker->data[10] == 0x45 &&
|
||||
marker->data[11] == 0x0;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,12 +102,12 @@ jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr,
|
||||
for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
|
||||
if (marker_is_icc(marker)) {
|
||||
if (num_markers == 0)
|
||||
num_markers = GETJOCTET(marker->data[13]);
|
||||
else if (num_markers != GETJOCTET(marker->data[13])) {
|
||||
num_markers = marker->data[13];
|
||||
else if (num_markers != marker->data[13]) {
|
||||
WARNMS(cinfo, JWRN_BOGUS_ICC); /* inconsistent num_markers fields */
|
||||
return FALSE;
|
||||
}
|
||||
seq_no = GETJOCTET(marker->data[12]);
|
||||
seq_no = marker->data[12];
|
||||
if (seq_no <= 0 || seq_no > num_markers) {
|
||||
WARNMS(cinfo, JWRN_BOGUS_ICC); /* bogus sequence number */
|
||||
return FALSE;
|
||||
@@ -154,7 +154,7 @@ jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr,
|
||||
JOCTET FAR *src_ptr;
|
||||
JOCTET *dst_ptr;
|
||||
unsigned int length;
|
||||
seq_no = GETJOCTET(marker->data[12]);
|
||||
seq_no = marker->data[12];
|
||||
dst_ptr = icc_data + data_offset[seq_no];
|
||||
src_ptr = marker->data + ICC_OVERHEAD_LEN;
|
||||
length = data_length[seq_no];
|
||||
|
||||
+32
-35
@@ -151,7 +151,7 @@ typedef my_marker_reader *my_marker_ptr;
|
||||
#define INPUT_BYTE(cinfo, V, action) \
|
||||
MAKESTMT( MAKE_BYTE_AVAIL(cinfo, action); \
|
||||
bytes_in_buffer--; \
|
||||
V = GETJOCTET(*next_input_byte++); )
|
||||
V = *next_input_byte++; )
|
||||
|
||||
/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
|
||||
* V should be declared unsigned int or perhaps JLONG.
|
||||
@@ -159,10 +159,10 @@ typedef my_marker_reader *my_marker_ptr;
|
||||
#define INPUT_2BYTES(cinfo, V, action) \
|
||||
MAKESTMT( MAKE_BYTE_AVAIL(cinfo, action); \
|
||||
bytes_in_buffer--; \
|
||||
V = ((unsigned int)GETJOCTET(*next_input_byte++)) << 8; \
|
||||
V = ((unsigned int)(*next_input_byte++)) << 8; \
|
||||
MAKE_BYTE_AVAIL(cinfo, action); \
|
||||
bytes_in_buffer--; \
|
||||
V += GETJOCTET(*next_input_byte++); )
|
||||
V += *next_input_byte++; )
|
||||
|
||||
|
||||
/*
|
||||
@@ -608,18 +608,18 @@ examine_app0(j_decompress_ptr cinfo, JOCTET *data, unsigned int datalen,
|
||||
JLONG totallen = (JLONG)datalen + remaining;
|
||||
|
||||
if (datalen >= APP0_DATA_LEN &&
|
||||
GETJOCTET(data[0]) == 0x4A &&
|
||||
GETJOCTET(data[1]) == 0x46 &&
|
||||
GETJOCTET(data[2]) == 0x49 &&
|
||||
GETJOCTET(data[3]) == 0x46 &&
|
||||
GETJOCTET(data[4]) == 0) {
|
||||
data[0] == 0x4A &&
|
||||
data[1] == 0x46 &&
|
||||
data[2] == 0x49 &&
|
||||
data[3] == 0x46 &&
|
||||
data[4] == 0) {
|
||||
/* Found JFIF APP0 marker: save info */
|
||||
cinfo->saw_JFIF_marker = TRUE;
|
||||
cinfo->JFIF_major_version = GETJOCTET(data[5]);
|
||||
cinfo->JFIF_minor_version = GETJOCTET(data[6]);
|
||||
cinfo->density_unit = GETJOCTET(data[7]);
|
||||
cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]);
|
||||
cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]);
|
||||
cinfo->JFIF_major_version = data[5];
|
||||
cinfo->JFIF_minor_version = data[6];
|
||||
cinfo->density_unit = data[7];
|
||||
cinfo->X_density = (data[8] << 8) + data[9];
|
||||
cinfo->Y_density = (data[10] << 8) + data[11];
|
||||
/* Check version.
|
||||
* Major version must be 1, anything else signals an incompatible change.
|
||||
* (We used to treat this as an error, but now it's a nonfatal warning,
|
||||
@@ -634,24 +634,22 @@ examine_app0(j_decompress_ptr cinfo, JOCTET *data, unsigned int datalen,
|
||||
cinfo->JFIF_major_version, cinfo->JFIF_minor_version,
|
||||
cinfo->X_density, cinfo->Y_density, cinfo->density_unit);
|
||||
/* Validate thumbnail dimensions and issue appropriate messages */
|
||||
if (GETJOCTET(data[12]) | GETJOCTET(data[13]))
|
||||
TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL,
|
||||
GETJOCTET(data[12]), GETJOCTET(data[13]));
|
||||
if (data[12] | data[13])
|
||||
TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, data[12], data[13]);
|
||||
totallen -= APP0_DATA_LEN;
|
||||
if (totallen !=
|
||||
((JLONG)GETJOCTET(data[12]) * (JLONG)GETJOCTET(data[13]) * (JLONG)3))
|
||||
if (totallen != ((JLONG)data[12] * (JLONG)data[13] * (JLONG)3))
|
||||
TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int)totallen);
|
||||
} else if (datalen >= 6 &&
|
||||
GETJOCTET(data[0]) == 0x4A &&
|
||||
GETJOCTET(data[1]) == 0x46 &&
|
||||
GETJOCTET(data[2]) == 0x58 &&
|
||||
GETJOCTET(data[3]) == 0x58 &&
|
||||
GETJOCTET(data[4]) == 0) {
|
||||
data[0] == 0x4A &&
|
||||
data[1] == 0x46 &&
|
||||
data[2] == 0x58 &&
|
||||
data[3] == 0x58 &&
|
||||
data[4] == 0) {
|
||||
/* Found JFIF "JFXX" extension APP0 marker */
|
||||
/* The library doesn't actually do anything with these,
|
||||
* but we try to produce a helpful trace message.
|
||||
*/
|
||||
switch (GETJOCTET(data[5])) {
|
||||
switch (data[5]) {
|
||||
case 0x10:
|
||||
TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int)totallen);
|
||||
break;
|
||||
@@ -662,8 +660,7 @@ examine_app0(j_decompress_ptr cinfo, JOCTET *data, unsigned int datalen,
|
||||
TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int)totallen);
|
||||
break;
|
||||
default:
|
||||
TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION,
|
||||
GETJOCTET(data[5]), (int)totallen);
|
||||
TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION, data[5], (int)totallen);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -684,16 +681,16 @@ examine_app14(j_decompress_ptr cinfo, JOCTET *data, unsigned int datalen,
|
||||
unsigned int version, flags0, flags1, transform;
|
||||
|
||||
if (datalen >= APP14_DATA_LEN &&
|
||||
GETJOCTET(data[0]) == 0x41 &&
|
||||
GETJOCTET(data[1]) == 0x64 &&
|
||||
GETJOCTET(data[2]) == 0x6F &&
|
||||
GETJOCTET(data[3]) == 0x62 &&
|
||||
GETJOCTET(data[4]) == 0x65) {
|
||||
data[0] == 0x41 &&
|
||||
data[1] == 0x64 &&
|
||||
data[2] == 0x6F &&
|
||||
data[3] == 0x62 &&
|
||||
data[4] == 0x65) {
|
||||
/* Found Adobe APP14 marker */
|
||||
version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]);
|
||||
flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]);
|
||||
flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]);
|
||||
transform = GETJOCTET(data[11]);
|
||||
version = (data[5] << 8) + data[6];
|
||||
flags0 = (data[7] << 8) + data[8];
|
||||
flags1 = (data[9] << 8) + data[10];
|
||||
transform = data[11];
|
||||
TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform);
|
||||
cinfo->saw_Adobe_marker = TRUE;
|
||||
cinfo->Adobe_transform = (UINT8)transform;
|
||||
|
||||
+2
-13
@@ -5,7 +5,7 @@
|
||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||
* Modified 2002-2009 by Guido Vollbeding.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2009-2011, 2016, D. R. Commander.
|
||||
* Copyright (C) 2009-2011, 2016, 2019, D. R. Commander.
|
||||
* Copyright (C) 2013, Linaro Limited.
|
||||
* Copyright (C) 2015, Google, Inc.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "jpeglib.h"
|
||||
#include "jpegcomp.h"
|
||||
#include "jdmaster.h"
|
||||
#include "jsimd.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -70,17 +69,6 @@ use_merged_upsample(j_decompress_ptr cinfo)
|
||||
cinfo->comp_info[1]._DCT_scaled_size != cinfo->_min_DCT_scaled_size ||
|
||||
cinfo->comp_info[2]._DCT_scaled_size != cinfo->_min_DCT_scaled_size)
|
||||
return FALSE;
|
||||
#ifdef WITH_SIMD
|
||||
/* If YCbCr-to-RGB color conversion is SIMD-accelerated but merged upsampling
|
||||
isn't, then disabling merged upsampling is likely to be faster when
|
||||
decompressing YCbCr JPEG images. */
|
||||
if (!jsimd_can_h2v2_merged_upsample() && !jsimd_can_h2v1_merged_upsample() &&
|
||||
jsimd_can_ycc_rgb() && cinfo->jpeg_color_space == JCS_YCbCr &&
|
||||
(cinfo->out_color_space == JCS_RGB ||
|
||||
(cinfo->out_color_space >= JCS_EXT_RGB &&
|
||||
cinfo->out_color_space <= JCS_EXT_ARGB)))
|
||||
return FALSE;
|
||||
#endif
|
||||
/* ??? also need to test for upsample-time rescaling, when & if supported */
|
||||
return TRUE; /* by golly, it'll work... */
|
||||
#else
|
||||
@@ -580,6 +568,7 @@ master_selection(j_decompress_ptr cinfo)
|
||||
*/
|
||||
cinfo->master->first_iMCU_col = 0;
|
||||
cinfo->master->last_iMCU_col = cinfo->MCUs_per_row - 1;
|
||||
cinfo->master->last_good_iMCU_row = 0;
|
||||
|
||||
#ifdef D_MULTISCAN_FILES_SUPPORTED
|
||||
/* If jpeg_start_decompress will read the whole file, initialize
|
||||
|
||||
+34
-34
@@ -43,20 +43,20 @@ h2v1_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
/* Loop for each pair of output pixels */
|
||||
for (col = cinfo->output_width >> 1; col > 0; col--) {
|
||||
/* Do the chroma part of the calculation */
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
|
||||
/* Fetch 2 Y values and emit 2 pixels */
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
y = *inptr0++;
|
||||
r = range_limit[y + cred];
|
||||
g = range_limit[y + cgreen];
|
||||
b = range_limit[y + cblue];
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
y = *inptr0++;
|
||||
r = range_limit[y + cred];
|
||||
g = range_limit[y + cgreen];
|
||||
b = range_limit[y + cblue];
|
||||
@@ -68,12 +68,12 @@ h2v1_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
|
||||
/* If image width is odd, do the last output column separately */
|
||||
if (cinfo->output_width & 1) {
|
||||
cb = GETJSAMPLE(*inptr1);
|
||||
cr = GETJSAMPLE(*inptr2);
|
||||
cb = *inptr1;
|
||||
cr = *inptr2;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
y = GETJSAMPLE(*inptr0);
|
||||
y = *inptr0;
|
||||
r = range_limit[y + cred];
|
||||
g = range_limit[y + cgreen];
|
||||
b = range_limit[y + cblue];
|
||||
@@ -115,21 +115,21 @@ h2v1_merged_upsample_565D_internal(j_decompress_ptr cinfo,
|
||||
/* Loop for each pair of output pixels */
|
||||
for (col = cinfo->output_width >> 1; col > 0; col--) {
|
||||
/* Do the chroma part of the calculation */
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
|
||||
/* Fetch 2 Y values and emit 2 pixels */
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
y = *inptr0++;
|
||||
r = range_limit[DITHER_565_R(y + cred, d0)];
|
||||
g = range_limit[DITHER_565_G(y + cgreen, d0)];
|
||||
b = range_limit[DITHER_565_B(y + cblue, d0)];
|
||||
d0 = DITHER_ROTATE(d0);
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
y = *inptr0++;
|
||||
r = range_limit[DITHER_565_R(y + cred, d0)];
|
||||
g = range_limit[DITHER_565_G(y + cgreen, d0)];
|
||||
b = range_limit[DITHER_565_B(y + cblue, d0)];
|
||||
@@ -142,12 +142,12 @@ h2v1_merged_upsample_565D_internal(j_decompress_ptr cinfo,
|
||||
|
||||
/* If image width is odd, do the last output column separately */
|
||||
if (cinfo->output_width & 1) {
|
||||
cb = GETJSAMPLE(*inptr1);
|
||||
cr = GETJSAMPLE(*inptr2);
|
||||
cb = *inptr1;
|
||||
cr = *inptr2;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
y = GETJSAMPLE(*inptr0);
|
||||
y = *inptr0;
|
||||
r = range_limit[DITHER_565_R(y + cred, d0)];
|
||||
g = range_limit[DITHER_565_G(y + cgreen, d0)];
|
||||
b = range_limit[DITHER_565_B(y + cblue, d0)];
|
||||
@@ -189,20 +189,20 @@ h2v2_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
/* Loop for each group of output pixels */
|
||||
for (col = cinfo->output_width >> 1; col > 0; col--) {
|
||||
/* Do the chroma part of the calculation */
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
|
||||
/* Fetch 4 Y values and emit 4 pixels */
|
||||
y = GETJSAMPLE(*inptr00++);
|
||||
y = *inptr00++;
|
||||
r = range_limit[y + cred];
|
||||
g = range_limit[y + cgreen];
|
||||
b = range_limit[y + cblue];
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
|
||||
y = GETJSAMPLE(*inptr00++);
|
||||
y = *inptr00++;
|
||||
r = range_limit[y + cred];
|
||||
g = range_limit[y + cgreen];
|
||||
b = range_limit[y + cblue];
|
||||
@@ -211,13 +211,13 @@ h2v2_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
WRITE_TWO_PIXELS(outptr0, rgb);
|
||||
outptr0 += 4;
|
||||
|
||||
y = GETJSAMPLE(*inptr01++);
|
||||
y = *inptr01++;
|
||||
r = range_limit[y + cred];
|
||||
g = range_limit[y + cgreen];
|
||||
b = range_limit[y + cblue];
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
|
||||
y = GETJSAMPLE(*inptr01++);
|
||||
y = *inptr01++;
|
||||
r = range_limit[y + cred];
|
||||
g = range_limit[y + cgreen];
|
||||
b = range_limit[y + cblue];
|
||||
@@ -229,20 +229,20 @@ h2v2_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
|
||||
/* If image width is odd, do the last output column separately */
|
||||
if (cinfo->output_width & 1) {
|
||||
cb = GETJSAMPLE(*inptr1);
|
||||
cr = GETJSAMPLE(*inptr2);
|
||||
cb = *inptr1;
|
||||
cr = *inptr2;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
|
||||
y = GETJSAMPLE(*inptr00);
|
||||
y = *inptr00;
|
||||
r = range_limit[y + cred];
|
||||
g = range_limit[y + cgreen];
|
||||
b = range_limit[y + cblue];
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
*(INT16 *)outptr0 = (INT16)rgb;
|
||||
|
||||
y = GETJSAMPLE(*inptr01);
|
||||
y = *inptr01;
|
||||
r = range_limit[y + cred];
|
||||
g = range_limit[y + cgreen];
|
||||
b = range_limit[y + cblue];
|
||||
@@ -287,21 +287,21 @@ h2v2_merged_upsample_565D_internal(j_decompress_ptr cinfo,
|
||||
/* Loop for each group of output pixels */
|
||||
for (col = cinfo->output_width >> 1; col > 0; col--) {
|
||||
/* Do the chroma part of the calculation */
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
|
||||
/* Fetch 4 Y values and emit 4 pixels */
|
||||
y = GETJSAMPLE(*inptr00++);
|
||||
y = *inptr00++;
|
||||
r = range_limit[DITHER_565_R(y + cred, d0)];
|
||||
g = range_limit[DITHER_565_G(y + cgreen, d0)];
|
||||
b = range_limit[DITHER_565_B(y + cblue, d0)];
|
||||
d0 = DITHER_ROTATE(d0);
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
|
||||
y = GETJSAMPLE(*inptr00++);
|
||||
y = *inptr00++;
|
||||
r = range_limit[DITHER_565_R(y + cred, d0)];
|
||||
g = range_limit[DITHER_565_G(y + cgreen, d0)];
|
||||
b = range_limit[DITHER_565_B(y + cblue, d0)];
|
||||
@@ -311,14 +311,14 @@ h2v2_merged_upsample_565D_internal(j_decompress_ptr cinfo,
|
||||
WRITE_TWO_PIXELS(outptr0, rgb);
|
||||
outptr0 += 4;
|
||||
|
||||
y = GETJSAMPLE(*inptr01++);
|
||||
y = *inptr01++;
|
||||
r = range_limit[DITHER_565_R(y + cred, d1)];
|
||||
g = range_limit[DITHER_565_G(y + cgreen, d1)];
|
||||
b = range_limit[DITHER_565_B(y + cblue, d1)];
|
||||
d1 = DITHER_ROTATE(d1);
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
|
||||
y = GETJSAMPLE(*inptr01++);
|
||||
y = *inptr01++;
|
||||
r = range_limit[DITHER_565_R(y + cred, d1)];
|
||||
g = range_limit[DITHER_565_G(y + cgreen, d1)];
|
||||
b = range_limit[DITHER_565_B(y + cblue, d1)];
|
||||
@@ -331,20 +331,20 @@ h2v2_merged_upsample_565D_internal(j_decompress_ptr cinfo,
|
||||
|
||||
/* If image width is odd, do the last output column separately */
|
||||
if (cinfo->output_width & 1) {
|
||||
cb = GETJSAMPLE(*inptr1);
|
||||
cr = GETJSAMPLE(*inptr2);
|
||||
cb = *inptr1;
|
||||
cr = *inptr2;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
|
||||
y = GETJSAMPLE(*inptr00);
|
||||
y = *inptr00;
|
||||
r = range_limit[DITHER_565_R(y + cred, d0)];
|
||||
g = range_limit[DITHER_565_G(y + cgreen, d0)];
|
||||
b = range_limit[DITHER_565_B(y + cblue, d0)];
|
||||
rgb = PACK_SHORT_565(r, g, b);
|
||||
*(INT16 *)outptr0 = (INT16)rgb;
|
||||
|
||||
y = GETJSAMPLE(*inptr01);
|
||||
y = *inptr01;
|
||||
r = range_limit[DITHER_565_R(y + cred, d1)];
|
||||
g = range_limit[DITHER_565_G(y + cgreen, d1)];
|
||||
b = range_limit[DITHER_565_B(y + cblue, d1)];
|
||||
|
||||
+17
-17
@@ -46,13 +46,13 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
/* Loop for each pair of output pixels */
|
||||
for (col = cinfo->output_width >> 1; col > 0; col--) {
|
||||
/* Do the chroma part of the calculation */
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
/* Fetch 2 Y values and emit 2 pixels */
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
y = *inptr0++;
|
||||
outptr[RGB_RED] = range_limit[y + cred];
|
||||
outptr[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr[RGB_BLUE] = range_limit[y + cblue];
|
||||
@@ -60,7 +60,7 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
outptr[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr += RGB_PIXELSIZE;
|
||||
y = GETJSAMPLE(*inptr0++);
|
||||
y = *inptr0++;
|
||||
outptr[RGB_RED] = range_limit[y + cred];
|
||||
outptr[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr[RGB_BLUE] = range_limit[y + cblue];
|
||||
@@ -71,12 +71,12 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
}
|
||||
/* If image width is odd, do the last output column separately */
|
||||
if (cinfo->output_width & 1) {
|
||||
cb = GETJSAMPLE(*inptr1);
|
||||
cr = GETJSAMPLE(*inptr2);
|
||||
cb = *inptr1;
|
||||
cr = *inptr2;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
y = GETJSAMPLE(*inptr0);
|
||||
y = *inptr0;
|
||||
outptr[RGB_RED] = range_limit[y + cred];
|
||||
outptr[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr[RGB_BLUE] = range_limit[y + cblue];
|
||||
@@ -120,13 +120,13 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
/* Loop for each group of output pixels */
|
||||
for (col = cinfo->output_width >> 1; col > 0; col--) {
|
||||
/* Do the chroma part of the calculation */
|
||||
cb = GETJSAMPLE(*inptr1++);
|
||||
cr = GETJSAMPLE(*inptr2++);
|
||||
cb = *inptr1++;
|
||||
cr = *inptr2++;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
/* Fetch 4 Y values and emit 4 pixels */
|
||||
y = GETJSAMPLE(*inptr00++);
|
||||
y = *inptr00++;
|
||||
outptr0[RGB_RED] = range_limit[y + cred];
|
||||
outptr0[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr0[RGB_BLUE] = range_limit[y + cblue];
|
||||
@@ -134,7 +134,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
outptr0[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr0 += RGB_PIXELSIZE;
|
||||
y = GETJSAMPLE(*inptr00++);
|
||||
y = *inptr00++;
|
||||
outptr0[RGB_RED] = range_limit[y + cred];
|
||||
outptr0[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr0[RGB_BLUE] = range_limit[y + cblue];
|
||||
@@ -142,7 +142,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
outptr0[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr0 += RGB_PIXELSIZE;
|
||||
y = GETJSAMPLE(*inptr01++);
|
||||
y = *inptr01++;
|
||||
outptr1[RGB_RED] = range_limit[y + cred];
|
||||
outptr1[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr1[RGB_BLUE] = range_limit[y + cblue];
|
||||
@@ -150,7 +150,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
outptr1[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
outptr1 += RGB_PIXELSIZE;
|
||||
y = GETJSAMPLE(*inptr01++);
|
||||
y = *inptr01++;
|
||||
outptr1[RGB_RED] = range_limit[y + cred];
|
||||
outptr1[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr1[RGB_BLUE] = range_limit[y + cblue];
|
||||
@@ -161,19 +161,19 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
|
||||
}
|
||||
/* If image width is odd, do the last output column separately */
|
||||
if (cinfo->output_width & 1) {
|
||||
cb = GETJSAMPLE(*inptr1);
|
||||
cr = GETJSAMPLE(*inptr2);
|
||||
cb = *inptr1;
|
||||
cr = *inptr2;
|
||||
cred = Crrtab[cr];
|
||||
cgreen = (int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
|
||||
cblue = Cbbtab[cb];
|
||||
y = GETJSAMPLE(*inptr00);
|
||||
y = *inptr00;
|
||||
outptr0[RGB_RED] = range_limit[y + cred];
|
||||
outptr0[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr0[RGB_BLUE] = range_limit[y + cblue];
|
||||
#ifdef RGB_ALPHA
|
||||
outptr0[RGB_ALPHA] = 0xFF;
|
||||
#endif
|
||||
y = GETJSAMPLE(*inptr01);
|
||||
y = *inptr01;
|
||||
outptr1[RGB_RED] = range_limit[y + cred];
|
||||
outptr1[RGB_GREEN] = range_limit[y + cgreen];
|
||||
outptr1[RGB_BLUE] = range_limit[y + cblue];
|
||||
|
||||
Vendored
+20
-28
@@ -4,7 +4,7 @@
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Copyright (C) 1995-1997, Thomas G. Lane.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2015-2016, 2018, D. R. Commander.
|
||||
* Copyright (C) 2015-2016, 2018-2021, D. R. Commander.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -41,25 +41,6 @@ typedef struct {
|
||||
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
|
||||
} savable_state;
|
||||
|
||||
/* This macro is to work around compilers with missing or broken
|
||||
* structure assignment. You'll need to fix this code if you have
|
||||
* such a compiler and you change MAX_COMPS_IN_SCAN.
|
||||
*/
|
||||
|
||||
#ifndef NO_STRUCT_ASSIGN
|
||||
#define ASSIGN_STATE(dest, src) ((dest) = (src))
|
||||
#else
|
||||
#if MAX_COMPS_IN_SCAN == 4
|
||||
#define ASSIGN_STATE(dest, src) \
|
||||
((dest).EOBRUN = (src).EOBRUN, \
|
||||
(dest).last_dc_val[0] = (src).last_dc_val[0], \
|
||||
(dest).last_dc_val[1] = (src).last_dc_val[1], \
|
||||
(dest).last_dc_val[2] = (src).last_dc_val[2], \
|
||||
(dest).last_dc_val[3] = (src).last_dc_val[3])
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct jpeg_entropy_decoder pub; /* public fields */
|
||||
|
||||
@@ -102,7 +83,7 @@ start_pass_phuff_decoder(j_decompress_ptr cinfo)
|
||||
boolean is_DC_band, bad;
|
||||
int ci, coefi, tbl;
|
||||
d_derived_tbl **pdtbl;
|
||||
int *coef_bit_ptr;
|
||||
int *coef_bit_ptr, *prev_coef_bit_ptr;
|
||||
jpeg_component_info *compptr;
|
||||
|
||||
is_DC_band = (cinfo->Ss == 0);
|
||||
@@ -143,8 +124,15 @@ start_pass_phuff_decoder(j_decompress_ptr cinfo)
|
||||
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
||||
int cindex = cinfo->cur_comp_info[ci]->component_index;
|
||||
coef_bit_ptr = &cinfo->coef_bits[cindex][0];
|
||||
prev_coef_bit_ptr = &cinfo->coef_bits[cindex + cinfo->num_components][0];
|
||||
if (!is_DC_band && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
|
||||
WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
|
||||
for (coefi = MIN(cinfo->Ss, 1); coefi <= MAX(cinfo->Se, 9); coefi++) {
|
||||
if (cinfo->input_scan_number > 1)
|
||||
prev_coef_bit_ptr[coefi] = coef_bit_ptr[coefi];
|
||||
else
|
||||
prev_coef_bit_ptr[coefi] = 0;
|
||||
}
|
||||
for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
|
||||
int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
|
||||
if (cinfo->Ah != expected)
|
||||
@@ -323,7 +311,7 @@ decode_mcu_DC_first(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
|
||||
/* Load up working state */
|
||||
BITREAD_LOAD_STATE(cinfo, entropy->bitstate);
|
||||
ASSIGN_STATE(state, entropy->saved);
|
||||
state = entropy->saved;
|
||||
|
||||
/* Outer loop handles each block in the MCU */
|
||||
|
||||
@@ -356,11 +344,12 @@ decode_mcu_DC_first(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
|
||||
/* Completed MCU, so update state */
|
||||
BITREAD_SAVE_STATE(cinfo, entropy->bitstate);
|
||||
ASSIGN_STATE(entropy->saved, state);
|
||||
entropy->saved = state;
|
||||
}
|
||||
|
||||
/* Account for restart interval (no-op if not using restarts) */
|
||||
entropy->restarts_to_go--;
|
||||
if (cinfo->restart_interval)
|
||||
entropy->restarts_to_go--;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -444,7 +433,8 @@ decode_mcu_AC_first(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
}
|
||||
|
||||
/* Account for restart interval (no-op if not using restarts) */
|
||||
entropy->restarts_to_go--;
|
||||
if (cinfo->restart_interval)
|
||||
entropy->restarts_to_go--;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -495,7 +485,8 @@ decode_mcu_DC_refine(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
BITREAD_SAVE_STATE(cinfo, entropy->bitstate);
|
||||
|
||||
/* Account for restart interval (no-op if not using restarts) */
|
||||
entropy->restarts_to_go--;
|
||||
if (cinfo->restart_interval)
|
||||
entropy->restarts_to_go--;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -638,7 +629,8 @@ decode_mcu_AC_refine(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
|
||||
}
|
||||
|
||||
/* Account for restart interval (no-op if not using restarts) */
|
||||
entropy->restarts_to_go--;
|
||||
if (cinfo->restart_interval)
|
||||
entropy->restarts_to_go--;
|
||||
|
||||
return TRUE;
|
||||
|
||||
@@ -676,7 +668,7 @@ jinit_phuff_decoder(j_decompress_ptr cinfo)
|
||||
/* Create progression status table */
|
||||
cinfo->coef_bits = (int (*)[DCTSIZE2])
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
|
||||
cinfo->num_components * DCTSIZE2 *
|
||||
cinfo->num_components * 2 * DCTSIZE2 *
|
||||
sizeof(int));
|
||||
coef_bit_ptr = &cinfo->coef_bits[0][0];
|
||||
for (ci = 0; ci < cinfo->num_components; ci++)
|
||||
|
||||
+22
-16
@@ -8,7 +8,7 @@
|
||||
* Copyright (C) 2010, 2015-2016, D. R. Commander.
|
||||
* Copyright (C) 2014, MIPS Technologies, Inc., California.
|
||||
* Copyright (C) 2015, Google, Inc.
|
||||
* Copyright (C) 2019, Arm Limited.
|
||||
* Copyright (C) 2019-2020, Arm Limited.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -177,7 +177,7 @@ int_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
outptr = output_data[outrow];
|
||||
outend = outptr + cinfo->output_width;
|
||||
while (outptr < outend) {
|
||||
invalue = *inptr++; /* don't need GETJSAMPLE() here */
|
||||
invalue = *inptr++;
|
||||
for (h = h_expand; h > 0; h--) {
|
||||
*outptr++ = invalue;
|
||||
}
|
||||
@@ -213,7 +213,7 @@ h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
outptr = output_data[inrow];
|
||||
outend = outptr + cinfo->output_width;
|
||||
while (outptr < outend) {
|
||||
invalue = *inptr++; /* don't need GETJSAMPLE() here */
|
||||
invalue = *inptr++;
|
||||
*outptr++ = invalue;
|
||||
*outptr++ = invalue;
|
||||
}
|
||||
@@ -242,7 +242,7 @@ h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
outptr = output_data[outrow];
|
||||
outend = outptr + cinfo->output_width;
|
||||
while (outptr < outend) {
|
||||
invalue = *inptr++; /* don't need GETJSAMPLE() here */
|
||||
invalue = *inptr++;
|
||||
*outptr++ = invalue;
|
||||
*outptr++ = invalue;
|
||||
}
|
||||
@@ -283,20 +283,20 @@ h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
inptr = input_data[inrow];
|
||||
outptr = output_data[inrow];
|
||||
/* Special case for first column */
|
||||
invalue = GETJSAMPLE(*inptr++);
|
||||
invalue = *inptr++;
|
||||
*outptr++ = (JSAMPLE)invalue;
|
||||
*outptr++ = (JSAMPLE)((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2);
|
||||
*outptr++ = (JSAMPLE)((invalue * 3 + inptr[0] + 2) >> 2);
|
||||
|
||||
for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
|
||||
/* General case: 3/4 * nearer pixel + 1/4 * further pixel */
|
||||
invalue = GETJSAMPLE(*inptr++) * 3;
|
||||
*outptr++ = (JSAMPLE)((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2);
|
||||
*outptr++ = (JSAMPLE)((invalue + GETJSAMPLE(*inptr) + 2) >> 2);
|
||||
invalue = (*inptr++) * 3;
|
||||
*outptr++ = (JSAMPLE)((invalue + inptr[-2] + 1) >> 2);
|
||||
*outptr++ = (JSAMPLE)((invalue + inptr[0] + 2) >> 2);
|
||||
}
|
||||
|
||||
/* Special case for last column */
|
||||
invalue = GETJSAMPLE(*inptr);
|
||||
*outptr++ = (JSAMPLE)((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2);
|
||||
invalue = *inptr;
|
||||
*outptr++ = (JSAMPLE)((invalue * 3 + inptr[-1] + 1) >> 2);
|
||||
*outptr++ = (JSAMPLE)invalue;
|
||||
}
|
||||
}
|
||||
@@ -338,7 +338,7 @@ h1v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
outptr = output_data[outrow++];
|
||||
|
||||
for (colctr = 0; colctr < compptr->downsampled_width; colctr++) {
|
||||
thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
|
||||
thiscolsum = (*inptr0++) * 3 + (*inptr1++);
|
||||
*outptr++ = (JSAMPLE)((thiscolsum + bias) >> 2);
|
||||
}
|
||||
}
|
||||
@@ -381,8 +381,8 @@ h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
outptr = output_data[outrow++];
|
||||
|
||||
/* Special case for first column */
|
||||
thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
|
||||
nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
|
||||
thiscolsum = (*inptr0++) * 3 + (*inptr1++);
|
||||
nextcolsum = (*inptr0++) * 3 + (*inptr1++);
|
||||
*outptr++ = (JSAMPLE)((thiscolsum * 4 + 8) >> 4);
|
||||
*outptr++ = (JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4);
|
||||
lastcolsum = thiscolsum; thiscolsum = nextcolsum;
|
||||
@@ -390,7 +390,7 @@ h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
|
||||
/* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */
|
||||
/* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */
|
||||
nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
|
||||
nextcolsum = (*inptr0++) * 3 + (*inptr1++);
|
||||
*outptr++ = (JSAMPLE)((thiscolsum * 3 + lastcolsum + 8) >> 4);
|
||||
*outptr++ = (JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4);
|
||||
lastcolsum = thiscolsum; thiscolsum = nextcolsum;
|
||||
@@ -477,7 +477,13 @@ jinit_upsampler(j_decompress_ptr cinfo)
|
||||
} else if (h_in_group == h_out_group &&
|
||||
v_in_group * 2 == v_out_group && do_fancy) {
|
||||
/* Non-fancy upsampling is handled by the generic method */
|
||||
upsample->methods[ci] = h1v2_fancy_upsample;
|
||||
#if defined(__arm__) || defined(__aarch64__) || \
|
||||
defined(_M_ARM) || defined(_M_ARM64)
|
||||
if (jsimd_can_h1v2_fancy_upsample())
|
||||
upsample->methods[ci] = jsimd_h1v2_fancy_upsample;
|
||||
else
|
||||
#endif
|
||||
upsample->methods[ci] = h1v2_fancy_upsample;
|
||||
upsample->pub.need_context_rows = TRUE;
|
||||
} else if (h_in_group * 2 == h_out_group &&
|
||||
v_in_group * 2 == v_out_group) {
|
||||
|
||||
Vendored
+13
@@ -207,6 +207,10 @@ JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code")
|
||||
#endif
|
||||
#endif
|
||||
JMESSAGE(JWRN_BOGUS_ICC, "Corrupt JPEG data: bad ICC marker")
|
||||
#if JPEG_LIB_VERSION < 70
|
||||
JMESSAGE(JERR_BAD_DROP_SAMPLING,
|
||||
"Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c")
|
||||
#endif
|
||||
|
||||
#ifdef JMAKE_ENUM_LIST
|
||||
|
||||
@@ -252,6 +256,15 @@ JMESSAGE(JWRN_BOGUS_ICC, "Corrupt JPEG data: bad ICC marker")
|
||||
(cinfo)->err->msg_parm.i[2] = (p3), \
|
||||
(cinfo)->err->msg_parm.i[3] = (p4), \
|
||||
(*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
|
||||
#define ERREXIT6(cinfo, code, p1, p2, p3, p4, p5, p6) \
|
||||
((cinfo)->err->msg_code = (code), \
|
||||
(cinfo)->err->msg_parm.i[0] = (p1), \
|
||||
(cinfo)->err->msg_parm.i[1] = (p2), \
|
||||
(cinfo)->err->msg_parm.i[2] = (p3), \
|
||||
(cinfo)->err->msg_parm.i[3] = (p4), \
|
||||
(cinfo)->err->msg_parm.i[4] = (p5), \
|
||||
(cinfo)->err->msg_parm.i[5] = (p6), \
|
||||
(*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
|
||||
#define ERREXITS(cinfo, code, str) \
|
||||
((cinfo)->err->msg_code = (code), \
|
||||
strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
|
||||
|
||||
+4
-4
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Copyright (C) 1991-1998, Thomas G. Lane.
|
||||
* Modification developed 2002-2009 by Guido Vollbeding.
|
||||
* Modification developed 2002-2018 by Guido Vollbeding.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2015, 2020, D. R. Commander.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
@@ -417,7 +417,7 @@ jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
|
||||
/*
|
||||
* Perform dequantization and inverse DCT on one block of coefficients,
|
||||
* producing a 7x7 output block.
|
||||
* producing a reduced-size 7x7 output block.
|
||||
*
|
||||
* Optimized algorithm with 12 multiplications in the 1-D kernel.
|
||||
* cK represents sqrt(2) * cos(K*pi/14).
|
||||
@@ -1258,7 +1258,7 @@ jpeg_idct_10x10(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
|
||||
/*
|
||||
* Perform dequantization and inverse DCT on one block of coefficients,
|
||||
* producing a 11x11 output block.
|
||||
* producing an 11x11 output block.
|
||||
*
|
||||
* Optimized algorithm with 24 multiplications in the 1-D kernel.
|
||||
* cK represents sqrt(2) * cos(K*pi/22).
|
||||
@@ -2398,7 +2398,7 @@ jpeg_idct_16x16(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
tmp0 = DEQUANTIZE(inptr[DCTSIZE * 0], quantptr[DCTSIZE * 0]);
|
||||
tmp0 = LEFT_SHIFT(tmp0, CONST_BITS);
|
||||
/* Add fudge factor here for final descale. */
|
||||
tmp0 += 1 << (CONST_BITS - PASS1_BITS - 1);
|
||||
tmp0 += ONE << (CONST_BITS - PASS1_BITS - 1);
|
||||
|
||||
z1 = DEQUANTIZE(inptr[DCTSIZE * 4], quantptr[DCTSIZE * 4]);
|
||||
tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
|
||||
|
||||
-35
@@ -43,25 +43,11 @@
|
||||
|
||||
#if BITS_IN_JSAMPLE == 8
|
||||
/* JSAMPLE should be the smallest type that will hold the values 0..255.
|
||||
* You can use a signed char by having GETJSAMPLE mask it with 0xFF.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_UNSIGNED_CHAR
|
||||
|
||||
typedef unsigned char JSAMPLE;
|
||||
#define GETJSAMPLE(value) ((int)(value))
|
||||
|
||||
#else /* not HAVE_UNSIGNED_CHAR */
|
||||
|
||||
typedef char JSAMPLE;
|
||||
#ifdef __CHAR_UNSIGNED__
|
||||
#define GETJSAMPLE(value) ((int)(value))
|
||||
#else
|
||||
#define GETJSAMPLE(value) ((int)(value) & 0xFF)
|
||||
#endif /* __CHAR_UNSIGNED__ */
|
||||
|
||||
#endif /* HAVE_UNSIGNED_CHAR */
|
||||
|
||||
#define MAXJSAMPLE 255
|
||||
#define CENTERJSAMPLE 128
|
||||
|
||||
@@ -97,22 +83,9 @@ typedef short JCOEF;
|
||||
* managers, this is also the data type passed to fread/fwrite.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_UNSIGNED_CHAR
|
||||
|
||||
typedef unsigned char JOCTET;
|
||||
#define GETJOCTET(value) (value)
|
||||
|
||||
#else /* not HAVE_UNSIGNED_CHAR */
|
||||
|
||||
typedef char JOCTET;
|
||||
#ifdef __CHAR_UNSIGNED__
|
||||
#define GETJOCTET(value) (value)
|
||||
#else
|
||||
#define GETJOCTET(value) ((value) & 0xFF)
|
||||
#endif /* __CHAR_UNSIGNED__ */
|
||||
|
||||
#endif /* HAVE_UNSIGNED_CHAR */
|
||||
|
||||
|
||||
/* These typedefs are used for various table entries and so forth.
|
||||
* They must be at least as wide as specified; but making them too big
|
||||
@@ -123,15 +96,7 @@ typedef char JOCTET;
|
||||
|
||||
/* UINT8 must hold at least the values 0..255. */
|
||||
|
||||
#ifdef HAVE_UNSIGNED_CHAR
|
||||
typedef unsigned char UINT8;
|
||||
#else /* not HAVE_UNSIGNED_CHAR */
|
||||
#ifdef __CHAR_UNSIGNED__
|
||||
typedef char UINT8;
|
||||
#else /* not __CHAR_UNSIGNED__ */
|
||||
typedef short UINT8;
|
||||
#endif /* __CHAR_UNSIGNED__ */
|
||||
#endif /* HAVE_UNSIGNED_CHAR */
|
||||
|
||||
/* UINT16 must hold at least the values 0..65535. */
|
||||
|
||||
|
||||
Vendored
+4
-1
@@ -5,7 +5,7 @@
|
||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||
* Modified 1997-2009 by Guido Vollbeding.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2015-2016, D. R. Commander.
|
||||
* Copyright (C) 2015-2016, 2019, D. R. Commander.
|
||||
* Copyright (C) 2015, Google, Inc.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
@@ -158,6 +158,9 @@ struct jpeg_decomp_master {
|
||||
JDIMENSION first_MCU_col[MAX_COMPONENTS];
|
||||
JDIMENSION last_MCU_col[MAX_COMPONENTS];
|
||||
boolean jinit_upsampler_no_alloc;
|
||||
|
||||
/* Last iMCU row that was successfully decoded */
|
||||
JDIMENSION last_good_iMCU_row;
|
||||
};
|
||||
|
||||
/* Input control module */
|
||||
|
||||
Vendored
+12
-15
@@ -479,7 +479,7 @@ color_quantize(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
for (col = width; col > 0; col--) {
|
||||
pixcode = 0;
|
||||
for (ci = 0; ci < nc; ci++) {
|
||||
pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]);
|
||||
pixcode += colorindex[ci][*ptrin++];
|
||||
}
|
||||
*ptrout++ = (JSAMPLE)pixcode;
|
||||
}
|
||||
@@ -506,9 +506,9 @@ color_quantize3(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
ptrin = input_buf[row];
|
||||
ptrout = output_buf[row];
|
||||
for (col = width; col > 0; col--) {
|
||||
pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]);
|
||||
pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]);
|
||||
pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]);
|
||||
pixcode = colorindex0[*ptrin++];
|
||||
pixcode += colorindex1[*ptrin++];
|
||||
pixcode += colorindex2[*ptrin++];
|
||||
*ptrout++ = (JSAMPLE)pixcode;
|
||||
}
|
||||
}
|
||||
@@ -552,7 +552,7 @@ quantize_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
* required amount of padding.
|
||||
*/
|
||||
*output_ptr +=
|
||||
colorindex_ci[GETJSAMPLE(*input_ptr) + dither[col_index]];
|
||||
colorindex_ci[*input_ptr + dither[col_index]];
|
||||
input_ptr += nc;
|
||||
output_ptr++;
|
||||
col_index = (col_index + 1) & ODITHER_MASK;
|
||||
@@ -595,12 +595,9 @@ quantize3_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
col_index = 0;
|
||||
|
||||
for (col = width; col > 0; col--) {
|
||||
pixcode =
|
||||
GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) + dither0[col_index]]);
|
||||
pixcode +=
|
||||
GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) + dither1[col_index]]);
|
||||
pixcode +=
|
||||
GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) + dither2[col_index]]);
|
||||
pixcode = colorindex0[(*input_ptr++) + dither0[col_index]];
|
||||
pixcode += colorindex1[(*input_ptr++) + dither1[col_index]];
|
||||
pixcode += colorindex2[(*input_ptr++) + dither2[col_index]];
|
||||
*output_ptr++ = (JSAMPLE)pixcode;
|
||||
col_index = (col_index + 1) & ODITHER_MASK;
|
||||
}
|
||||
@@ -677,15 +674,15 @@ quantize_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
* The maximum error is +- MAXJSAMPLE; this sets the required size
|
||||
* of the range_limit array.
|
||||
*/
|
||||
cur += GETJSAMPLE(*input_ptr);
|
||||
cur = GETJSAMPLE(range_limit[cur]);
|
||||
cur += *input_ptr;
|
||||
cur = range_limit[cur];
|
||||
/* Select output value, accumulate into output code for this pixel */
|
||||
pixcode = GETJSAMPLE(colorindex_ci[cur]);
|
||||
pixcode = colorindex_ci[cur];
|
||||
*output_ptr += (JSAMPLE)pixcode;
|
||||
/* Compute actual representation error at this pixel */
|
||||
/* Note: we can do this even though we don't have the final */
|
||||
/* pixel code, because the colormap is orthogonal. */
|
||||
cur -= GETJSAMPLE(colormap_ci[pixcode]);
|
||||
cur -= colormap_ci[pixcode];
|
||||
/* Compute error fractions to be propagated to adjacent pixels.
|
||||
* Add these into the running sums, and simultaneously shift the
|
||||
* next-line error sums left by 1 column.
|
||||
|
||||
Vendored
+23
-23
@@ -215,9 +215,9 @@ prescan_quantize(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
ptr = input_buf[row];
|
||||
for (col = width; col > 0; col--) {
|
||||
/* get pixel value and index into the histogram */
|
||||
histp = &histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT]
|
||||
[GETJSAMPLE(ptr[1]) >> C1_SHIFT]
|
||||
[GETJSAMPLE(ptr[2]) >> C2_SHIFT];
|
||||
histp = &histogram[ptr[0] >> C0_SHIFT]
|
||||
[ptr[1] >> C1_SHIFT]
|
||||
[ptr[2] >> C2_SHIFT];
|
||||
/* increment, check for overflow and undo increment if so. */
|
||||
if (++(*histp) <= 0)
|
||||
(*histp)--;
|
||||
@@ -665,7 +665,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
|
||||
|
||||
for (i = 0; i < numcolors; i++) {
|
||||
/* We compute the squared-c0-distance term, then add in the other two. */
|
||||
x = GETJSAMPLE(cinfo->colormap[0][i]);
|
||||
x = cinfo->colormap[0][i];
|
||||
if (x < minc0) {
|
||||
tdist = (x - minc0) * C0_SCALE;
|
||||
min_dist = tdist * tdist;
|
||||
@@ -688,7 +688,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
|
||||
}
|
||||
}
|
||||
|
||||
x = GETJSAMPLE(cinfo->colormap[1][i]);
|
||||
x = cinfo->colormap[1][i];
|
||||
if (x < minc1) {
|
||||
tdist = (x - minc1) * C1_SCALE;
|
||||
min_dist += tdist * tdist;
|
||||
@@ -710,7 +710,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
|
||||
}
|
||||
}
|
||||
|
||||
x = GETJSAMPLE(cinfo->colormap[2][i]);
|
||||
x = cinfo->colormap[2][i];
|
||||
if (x < minc2) {
|
||||
tdist = (x - minc2) * C2_SCALE;
|
||||
min_dist += tdist * tdist;
|
||||
@@ -788,13 +788,13 @@ find_best_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
|
||||
#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE)
|
||||
|
||||
for (i = 0; i < numcolors; i++) {
|
||||
icolor = GETJSAMPLE(colorlist[i]);
|
||||
icolor = colorlist[i];
|
||||
/* Compute (square of) distance from minc0/c1/c2 to this color */
|
||||
inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE;
|
||||
inc0 = (minc0 - cinfo->colormap[0][icolor]) * C0_SCALE;
|
||||
dist0 = inc0 * inc0;
|
||||
inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE;
|
||||
inc1 = (minc1 - cinfo->colormap[1][icolor]) * C1_SCALE;
|
||||
dist0 += inc1 * inc1;
|
||||
inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE;
|
||||
inc2 = (minc2 - cinfo->colormap[2][icolor]) * C2_SCALE;
|
||||
dist0 += inc2 * inc2;
|
||||
/* Form the initial difference increments */
|
||||
inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;
|
||||
@@ -879,7 +879,7 @@ fill_inverse_cmap(j_decompress_ptr cinfo, int c0, int c1, int c2)
|
||||
for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) {
|
||||
cachep = &histogram[c0 + ic0][c1 + ic1][c2];
|
||||
for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) {
|
||||
*cachep++ = (histcell)(GETJSAMPLE(*cptr++) + 1);
|
||||
*cachep++ = (histcell)((*cptr++) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -909,9 +909,9 @@ pass2_no_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
outptr = output_buf[row];
|
||||
for (col = width; col > 0; col--) {
|
||||
/* get pixel value and index into the cache */
|
||||
c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT;
|
||||
c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT;
|
||||
c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT;
|
||||
c0 = (*inptr++) >> C0_SHIFT;
|
||||
c1 = (*inptr++) >> C1_SHIFT;
|
||||
c2 = (*inptr++) >> C2_SHIFT;
|
||||
cachep = &histogram[c0][c1][c2];
|
||||
/* If we have not seen this color before, find nearest colormap entry */
|
||||
/* and update the cache */
|
||||
@@ -996,12 +996,12 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
* The maximum error is +- MAXJSAMPLE (or less with error limiting);
|
||||
* this sets the required size of the range_limit array.
|
||||
*/
|
||||
cur0 += GETJSAMPLE(inptr[0]);
|
||||
cur1 += GETJSAMPLE(inptr[1]);
|
||||
cur2 += GETJSAMPLE(inptr[2]);
|
||||
cur0 = GETJSAMPLE(range_limit[cur0]);
|
||||
cur1 = GETJSAMPLE(range_limit[cur1]);
|
||||
cur2 = GETJSAMPLE(range_limit[cur2]);
|
||||
cur0 += inptr[0];
|
||||
cur1 += inptr[1];
|
||||
cur2 += inptr[2];
|
||||
cur0 = range_limit[cur0];
|
||||
cur1 = range_limit[cur1];
|
||||
cur2 = range_limit[cur2];
|
||||
/* Index into the cache with adjusted pixel value */
|
||||
cachep =
|
||||
&histogram[cur0 >> C0_SHIFT][cur1 >> C1_SHIFT][cur2 >> C2_SHIFT];
|
||||
@@ -1015,9 +1015,9 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
|
||||
register int pixcode = *cachep - 1;
|
||||
*outptr = (JSAMPLE)pixcode;
|
||||
/* Compute representation error for this pixel */
|
||||
cur0 -= GETJSAMPLE(colormap0[pixcode]);
|
||||
cur1 -= GETJSAMPLE(colormap1[pixcode]);
|
||||
cur2 -= GETJSAMPLE(colormap2[pixcode]);
|
||||
cur0 -= colormap0[pixcode];
|
||||
cur1 -= colormap1[pixcode];
|
||||
cur2 -= colormap2[pixcode];
|
||||
}
|
||||
/* Compute error fractions to be propagated to adjacent pixels.
|
||||
* Add these into the running sums, and simultaneously shift the
|
||||
|
||||
Vendored
+6
@@ -4,6 +4,7 @@
|
||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||
* Copyright (C) 2011, 2014, D. R. Commander.
|
||||
* Copyright (C) 2015-2016, 2018, Matthieu Darbois.
|
||||
* Copyright (C) 2020, Arm Limited.
|
||||
*
|
||||
* Based on the x86 SIMD extension for IJG JPEG library,
|
||||
* Copyright (C) 1999-2006, MIYASAKA Masaru.
|
||||
@@ -75,6 +76,7 @@ EXTERN(void) jsimd_int_upsample(j_decompress_ptr cinfo,
|
||||
|
||||
EXTERN(int) jsimd_can_h2v2_fancy_upsample(void);
|
||||
EXTERN(int) jsimd_can_h2v1_fancy_upsample(void);
|
||||
EXTERN(int) jsimd_can_h1v2_fancy_upsample(void);
|
||||
|
||||
EXTERN(void) jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo,
|
||||
jpeg_component_info *compptr,
|
||||
@@ -84,6 +86,10 @@ EXTERN(void) jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo,
|
||||
jpeg_component_info *compptr,
|
||||
JSAMPARRAY input_data,
|
||||
JSAMPARRAY *output_data_ptr);
|
||||
EXTERN(void) jsimd_h1v2_fancy_upsample(j_decompress_ptr cinfo,
|
||||
jpeg_component_info *compptr,
|
||||
JSAMPARRAY input_data,
|
||||
JSAMPARRAY *output_data_ptr);
|
||||
|
||||
EXTERN(int) jsimd_can_h2v2_merged_upsample(void);
|
||||
EXTERN(int) jsimd_can_h2v1_merged_upsample(void);
|
||||
|
||||
+13
@@ -4,6 +4,7 @@
|
||||
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
||||
* Copyright (C) 2009-2011, 2014, D. R. Commander.
|
||||
* Copyright (C) 2015-2016, 2018, Matthieu Darbois.
|
||||
* Copyright (C) 2020, Arm Limited.
|
||||
*
|
||||
* Based on the x86 SIMD extension for IJG JPEG library,
|
||||
* Copyright (C) 1999-2006, MIYASAKA Masaru.
|
||||
@@ -169,6 +170,12 @@ jsimd_can_h2v1_fancy_upsample(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLOBAL(int)
|
||||
jsimd_can_h1v2_fancy_upsample(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
|
||||
@@ -181,6 +188,12 @@ jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
{
|
||||
}
|
||||
|
||||
GLOBAL(void)
|
||||
jsimd_h1v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
|
||||
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
|
||||
{
|
||||
}
|
||||
|
||||
GLOBAL(int)
|
||||
jsimd_can_h2v2_merged_upsample(void)
|
||||
{
|
||||
|
||||
+6
-6
@@ -2,9 +2,9 @@
|
||||
* jversion.h
|
||||
*
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding.
|
||||
* Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2010, 2012-2020, D. R. Commander.
|
||||
* Copyright (C) 2010, 2012-2021, D. R. Commander.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -37,9 +37,9 @@
|
||||
*/
|
||||
|
||||
#define JCOPYRIGHT \
|
||||
"Copyright (C) 2009-2020 D. R. Commander\n" \
|
||||
"Copyright (C) 2009-2021 D. R. Commander\n" \
|
||||
"Copyright (C) 2015, 2020 Google, Inc.\n" \
|
||||
"Copyright (C) 2019 Arm Limited\n" \
|
||||
"Copyright (C) 2019-2020 Arm Limited\n" \
|
||||
"Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \
|
||||
"Copyright (C) 2011-2016 Siarhei Siamashka\n" \
|
||||
"Copyright (C) 2015 Intel Corporation\n" \
|
||||
@@ -48,7 +48,7 @@
|
||||
"Copyright (C) 2009, 2012 Pierre Ossman for Cendio AB\n" \
|
||||
"Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \
|
||||
"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
|
||||
"Copyright (C) 1991-2017 Thomas G. Lane, Guido Vollbeding"
|
||||
"Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding"
|
||||
|
||||
#define JCOPYRIGHT_SHORT \
|
||||
"Copyright (C) 1991-2020 The libjpeg-turbo Project and many others"
|
||||
"Copyright (C) 1991-2021 The libjpeg-turbo Project and many others"
|
||||
|
||||
+30
-10
@@ -238,7 +238,7 @@ OCV_OPTION(WITH_CAP_IOS "Enable iOS video capture" ON
|
||||
VISIBLE_IF IOS
|
||||
VERIFY HAVE_CAP_IOS)
|
||||
OCV_OPTION(WITH_CAROTENE "Use NVidia carotene acceleration library for ARM platform" ON
|
||||
VISIBLE_IF (ARM OR AARCH64) AND NOT IOS AND NOT (CMAKE_VERSION VERSION_LESS "2.8.11"))
|
||||
VISIBLE_IF (ARM OR AARCH64) AND NOT IOS)
|
||||
OCV_OPTION(WITH_CPUFEATURES "Use cpufeatures Android library" ON
|
||||
VISIBLE_IF ANDROID
|
||||
VERIFY HAVE_CPUFEATURES)
|
||||
@@ -467,6 +467,7 @@ OCV_OPTION(BUILD_ANDROID_SERVICE "Build OpenCV Manager for Google Play" OFF I
|
||||
OCV_OPTION(BUILD_CUDA_STUBS "Build CUDA modules stubs when no CUDA SDK" OFF IF (NOT APPLE_FRAMEWORK) )
|
||||
OCV_OPTION(BUILD_JAVA "Enable Java support" (ANDROID OR NOT CMAKE_CROSSCOMPILING) IF (ANDROID OR (NOT APPLE_FRAMEWORK AND NOT WINRT)) )
|
||||
OCV_OPTION(BUILD_OBJC "Enable Objective-C support" ON IF APPLE_FRAMEWORK )
|
||||
OCV_OPTION(BUILD_KOTLIN_EXTENSIONS "Build Kotlin extensions (Android)" ON IF ANDROID )
|
||||
|
||||
# OpenCV installation options
|
||||
# ===================================================
|
||||
@@ -498,7 +499,7 @@ OCV_OPTION(OPENCV_WARNINGS_ARE_ERRORS "Treat warnings as errors"
|
||||
OCV_OPTION(ANDROID_EXAMPLES_WITH_LIBS "Build binaries of Android examples with native libraries" OFF IF ANDROID )
|
||||
OCV_OPTION(ENABLE_IMPL_COLLECTION "Collect implementation data on function call" OFF )
|
||||
OCV_OPTION(ENABLE_INSTRUMENTATION "Instrument functions to collect calls trace and performance" OFF )
|
||||
OCV_OPTION(ENABLE_GNU_STL_DEBUG "Enable GNU STL Debug mode (defines _GLIBCXX_DEBUG)" OFF IF ((NOT CMAKE_VERSION VERSION_LESS "2.8.11") AND CV_GCC) )
|
||||
OCV_OPTION(ENABLE_GNU_STL_DEBUG "Enable GNU STL Debug mode (defines _GLIBCXX_DEBUG)" OFF IF CV_GCC )
|
||||
OCV_OPTION(ENABLE_BUILD_HARDENING "Enable hardening of the resulting binaries (against security attacks, detects memory corruption, etc)" OFF)
|
||||
OCV_OPTION(ENABLE_LTO "Enable Link Time Optimization" OFF IF CV_GCC OR MSVC)
|
||||
OCV_OPTION(ENABLE_THIN_LTO "Enable Thin LTO" OFF IF CV_CLANG)
|
||||
@@ -510,6 +511,7 @@ 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(OPENCV_DISABLE_FILESYSTEM_SUPPORT "Disable filesystem support" OFF)
|
||||
|
||||
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) )
|
||||
@@ -518,6 +520,10 @@ if(ENABLE_IMPL_COLLECTION)
|
||||
add_definitions(-DCV_COLLECT_IMPL_DATA)
|
||||
endif()
|
||||
|
||||
if(OPENCV_DISABLE_FILESYSTEM_SUPPORT)
|
||||
add_definitions(-DOPENCV_HAVE_FILESYSTEM_SUPPORT=0)
|
||||
endif()
|
||||
|
||||
set(OPENCV_MATHJAX_RELPATH "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0" CACHE STRING "URI to a MathJax installation")
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -651,6 +657,8 @@ if(UNIX)
|
||||
set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} m pthread)
|
||||
elseif(EMSCRIPTEN)
|
||||
# no need to link to system libs with emscripten
|
||||
elseif(QNXNTO)
|
||||
# no need to link to system libs with QNX
|
||||
else()
|
||||
set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} dl m pthread rt)
|
||||
endif()
|
||||
@@ -999,6 +1007,12 @@ if(COMMAND ocv_pylint_finalize)
|
||||
ocv_pylint_add_directory_recurse(${CMAKE_CURRENT_LIST_DIR}/samples/python/tutorial_code)
|
||||
ocv_pylint_finalize()
|
||||
endif()
|
||||
if(TARGET check_pylint)
|
||||
message(STATUS "Registered 'check_pylint' target: using ${PYLINT_EXECUTABLE} (ver: ${PYLINT_VERSION}), checks: ${PYLINT_TOTAL_TARGETS}")
|
||||
endif()
|
||||
if(TARGET check_flake8)
|
||||
message(STATUS "Registered 'check_flake8' target: using ${FLAKE8_EXECUTABLE} (ver: ${FLAKE8_VERSION})")
|
||||
endif()
|
||||
|
||||
if(OPENCV_GENERATE_SETUPVARS)
|
||||
include(cmake/OpenCVGenSetupVars.cmake)
|
||||
@@ -1035,7 +1049,6 @@ endif()
|
||||
status("")
|
||||
status(" Platform:")
|
||||
if(NOT DEFINED OPENCV_TIMESTAMP
|
||||
AND NOT CMAKE_VERSION VERSION_LESS 2.8.11
|
||||
AND NOT BUILD_INFO_SKIP_TIMESTAMP
|
||||
)
|
||||
string(TIMESTAMP OPENCV_TIMESTAMP "" UTC)
|
||||
@@ -1120,6 +1133,10 @@ endif()
|
||||
status(" ccache:" OPENCV_COMPILER_IS_CCACHE THEN YES ELSE NO)
|
||||
status(" Precompiled headers:" PCHSupport_FOUND AND ENABLE_PRECOMPILED_HEADERS THEN YES ELSE NO)
|
||||
|
||||
if(OPENCV_DISABLE_FILESYSTEM_SUPPORT)
|
||||
status(" Filesystem support is disabled")
|
||||
endif()
|
||||
|
||||
# ========================== Dependencies ============================
|
||||
ocv_get_all_libs(deps_modules deps_extra deps_3rdparty)
|
||||
status(" Extra dependencies:" ${deps_extra})
|
||||
@@ -1415,7 +1432,16 @@ if(WITH_LIBREALSENSE OR HAVE_LIBREALSENSE)
|
||||
endif()
|
||||
|
||||
if(WITH_MFX OR HAVE_MFX)
|
||||
status(" Intel Media SDK:" HAVE_MFX THEN "YES (${MFX_LIBRARY})" ELSE NO)
|
||||
if(HAVE_MFX)
|
||||
if(MFX_LIBRARY)
|
||||
set(__details " (${MFX_LIBRARY})")
|
||||
elseif(MFX_LIBRARIES)
|
||||
set(__details " (${MFX_LIBRARIES})")
|
||||
else()
|
||||
set(__details " (unknown)")
|
||||
endif()
|
||||
endif()
|
||||
status(" Intel Media SDK:" HAVE_MFX THEN "YES${__details}" ELSE NO)
|
||||
endif()
|
||||
|
||||
if(WITH_GPHOTO2 OR HAVE_GPHOTO2)
|
||||
@@ -1628,12 +1654,6 @@ endif()
|
||||
|
||||
status("")
|
||||
status(" Python (for build):" PYTHON_DEFAULT_AVAILABLE THEN "${PYTHON_DEFAULT_EXECUTABLE}" ELSE NO)
|
||||
if(PYLINT_FOUND AND PYLINT_EXECUTABLE)
|
||||
status(" Pylint:" PYLINT_FOUND THEN "${PYLINT_EXECUTABLE} (ver: ${PYLINT_VERSION}, checks: ${PYLINT_TOTAL_TARGETS})" ELSE NO)
|
||||
endif()
|
||||
if(FLAKE8_FOUND AND FLAKE8_EXECUTABLE)
|
||||
status(" Flake8:" FLAKE8_FOUND THEN "${FLAKE8_EXECUTABLE} (ver: ${FLAKE8_VERSION})" ELSE NO)
|
||||
endif()
|
||||
|
||||
# ========================== java ==========================
|
||||
if(BUILD_JAVA)
|
||||
|
||||
@@ -59,3 +59,4 @@ ocv_add_app(annotation)
|
||||
ocv_add_app(visualisation)
|
||||
ocv_add_app(interactive-calibration)
|
||||
ocv_add_app(version)
|
||||
ocv_add_app(model-diagnostics)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
ocv_add_application(opencv_model_diagnostics
|
||||
MODULES opencv_core opencv_dnn
|
||||
SRCS model_diagnostics.cpp)
|
||||
@@ -0,0 +1,65 @@
|
||||
/*************************************************
|
||||
USAGE:
|
||||
./model_diagnostics -m <model file location>
|
||||
**************************************************/
|
||||
#include <opencv2/dnn.hpp>
|
||||
#include <opencv2/core/utils/filesystem.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
using namespace cv;
|
||||
using namespace dnn;
|
||||
|
||||
|
||||
static
|
||||
int diagnosticsErrorCallback(int /*status*/, const char* /*func_name*/,
|
||||
const char* /*err_msg*/, const char* /*file_name*/,
|
||||
int /*line*/, void* /*userdata*/)
|
||||
{
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::string checkFileExists(const std::string& fileName)
|
||||
{
|
||||
if (fileName.empty() || utils::fs::exists(fileName))
|
||||
return fileName;
|
||||
|
||||
CV_Error(Error::StsObjectNotFound, "File " + fileName + " was not found! "
|
||||
"Please, specify a full path to the file.");
|
||||
}
|
||||
|
||||
std::string diagnosticKeys =
|
||||
"{ model m | | Path to the model file. }"
|
||||
"{ config c | | Path to the model configuration file. }"
|
||||
"{ framework f | | [Optional] Name of the model framework. }";
|
||||
|
||||
|
||||
|
||||
int main( int argc, const char** argv )
|
||||
{
|
||||
CommandLineParser argParser(argc, argv, diagnosticKeys);
|
||||
argParser.about("Use this tool to run the diagnostics of provided ONNX/TF model"
|
||||
"to obtain the information about its support (supported layers).");
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
argParser.printMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string model = checkFileExists(argParser.get<std::string>("model"));
|
||||
std::string config = checkFileExists(argParser.get<std::string>("config"));
|
||||
std::string frameworkId = argParser.get<std::string>("framework");
|
||||
|
||||
CV_Assert(!model.empty());
|
||||
|
||||
enableModelDiagnostics(true);
|
||||
redirectError(diagnosticsErrorCallback, NULL);
|
||||
|
||||
Net ocvNet = readNet(model, config, frameworkId);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ if(PYLINT_EXECUTABLE AND NOT DEFINED PYLINT_VERSION)
|
||||
execute_process(COMMAND ${PYLINT_EXECUTABLE} --version RESULT_VARIABLE _result OUTPUT_VARIABLE PYLINT_VERSION_RAW)
|
||||
if(NOT _result EQUAL 0)
|
||||
ocv_clear_vars(PYLINT_EXECUTABLE PYLINT_VERSION)
|
||||
elseif(PYLINT_VERSION_RAW MATCHES "pylint([^,]*) ([0-9\\.]+[0-9])")
|
||||
elseif(PYLINT_VERSION_RAW MATCHES "pylint([^,\n]*) ([0-9\\.]+[0-9])")
|
||||
set(PYLINT_VERSION "${CMAKE_MATCH_2}")
|
||||
else()
|
||||
set(PYLINT_VERSION "unknown")
|
||||
|
||||
@@ -179,7 +179,13 @@ if(CV_GCC OR CV_CLANG)
|
||||
endif()
|
||||
|
||||
# We need pthread's
|
||||
if(UNIX AND NOT ANDROID AND NOT (APPLE AND CV_CLANG)) # TODO
|
||||
if((UNIX
|
||||
AND NOT ANDROID
|
||||
AND NOT (APPLE AND CV_CLANG)
|
||||
AND NOT EMSCRIPTEN
|
||||
)
|
||||
OR (EMSCRIPTEN AND WITH_PTHREADS_PF) # https://github.com/opencv/opencv/issues/20285
|
||||
)
|
||||
add_extra_compiler_option(-pthread)
|
||||
endif()
|
||||
|
||||
@@ -227,9 +233,11 @@ if(CV_GCC OR CV_CLANG)
|
||||
if(APPLE)
|
||||
set(OPENCV_EXTRA_EXE_LINKER_FLAGS "${OPENCV_EXTRA_EXE_LINKER_FLAGS} -Wl,-dead_strip")
|
||||
set(OPENCV_EXTRA_SHARED_LINKER_FLAGS "${OPENCV_EXTRA_SHARED_LINKER_FLAGS} -Wl,-dead_strip")
|
||||
set(OPENCV_EXTRA_MODULE_LINKER_FLAGS "${OPENCV_EXTRA_MODULE_LINKER_FLAGS} -Wl,-dead_strip")
|
||||
else()
|
||||
set(OPENCV_EXTRA_EXE_LINKER_FLAGS "${OPENCV_EXTRA_EXE_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
set(OPENCV_EXTRA_SHARED_LINKER_FLAGS "${OPENCV_EXTRA_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
set(OPENCV_EXTRA_MODULE_LINKER_FLAGS "${OPENCV_EXTRA_MODULE_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -281,6 +289,7 @@ if(MSVC)
|
||||
set(OPENCV_EXTRA_FLAGS_RELEASE "${OPENCV_EXTRA_FLAGS_RELEASE} /Zi")
|
||||
set(OPENCV_EXTRA_EXE_LINKER_FLAGS_RELEASE "${OPENCV_EXTRA_EXE_LINKER_FLAGS_RELEASE} /debug")
|
||||
set(OPENCV_EXTRA_SHARED_LINKER_FLAGS_RELEASE "${OPENCV_EXTRA_SHARED_LINKER_FLAGS_RELEASE} /debug")
|
||||
set(OPENCV_EXTRA_MODULE_LINKER_FLAGS_RELEASE "${OPENCV_EXTRA_MODULE_LINKER_FLAGS_RELEASE} /debug")
|
||||
endif()
|
||||
|
||||
# Remove unreferenced functions: function level linking
|
||||
@@ -350,6 +359,7 @@ if(NOT OPENCV_SKIP_LINK_AS_NEEDED)
|
||||
if(HAVE_LINK_AS_NEEDED)
|
||||
set(OPENCV_EXTRA_EXE_LINKER_FLAGS "${OPENCV_EXTRA_EXE_LINKER_FLAGS} ${_option}")
|
||||
set(OPENCV_EXTRA_SHARED_LINKER_FLAGS "${OPENCV_EXTRA_SHARED_LINKER_FLAGS} ${_option}")
|
||||
set(OPENCV_EXTRA_MODULE_LINKER_FLAGS "${OPENCV_EXTRA_MODULE_LINKER_FLAGS} ${_option}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -368,6 +378,9 @@ if(NOT OPENCV_SKIP_EXTRA_COMPILER_FLAGS)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${OPENCV_EXTRA_SHARED_LINKER_FLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${OPENCV_EXTRA_SHARED_LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${OPENCV_EXTRA_SHARED_LINKER_FLAGS_DEBUG}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${OPENCV_EXTRA_MODULE_LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${OPENCV_EXTRA_MODULE_LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} ${OPENCV_EXTRA_MODULE_LINKER_FLAGS_DEBUG}")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
|
||||
@@ -9,9 +9,14 @@ set(HALIDE_ROOT_DIR "${HALIDE_ROOT_DIR}" CACHE PATH "Halide root directory")
|
||||
if(NOT HAVE_HALIDE)
|
||||
find_package(Halide QUIET) # Try CMake-based config files
|
||||
if(Halide_FOUND)
|
||||
set(HALIDE_INCLUDE_DIRS "${Halide_INCLUDE_DIRS}" CACHE PATH "Halide include directories" FORCE)
|
||||
set(HALIDE_LIBRARIES "${Halide_LIBRARIES}" CACHE PATH "Halide libraries" FORCE)
|
||||
set(HAVE_HALIDE TRUE)
|
||||
if(TARGET Halide::Halide) # modern Halide scripts defines imported target
|
||||
set(HALIDE_INCLUDE_DIRS "")
|
||||
set(HALIDE_LIBRARIES "Halide::Halide")
|
||||
set(HAVE_HALIDE TRUE)
|
||||
else()
|
||||
# using HALIDE_INCLUDE_DIRS / Halide_LIBRARIES
|
||||
set(HAVE_HALIDE TRUE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -28,18 +33,15 @@ if(NOT HAVE_HALIDE AND HALIDE_ROOT_DIR)
|
||||
)
|
||||
if(HALIDE_LIBRARY AND HALIDE_INCLUDE_DIR)
|
||||
# TODO try_compile
|
||||
set(HALIDE_INCLUDE_DIRS "${HALIDE_INCLUDE_DIR}" CACHE PATH "Halide include directories" FORCE)
|
||||
set(HALIDE_LIBRARIES "${HALIDE_LIBRARY}" CACHE PATH "Halide libraries" FORCE)
|
||||
set(HALIDE_INCLUDE_DIRS "${HALIDE_INCLUDE_DIR}")
|
||||
set(HALIDE_LIBRARIES "${HALIDE_LIBRARY}")
|
||||
set(HAVE_HALIDE TRUE)
|
||||
endif()
|
||||
if(NOT HAVE_HALIDE)
|
||||
ocv_clear_vars(HALIDE_LIBRARIES HALIDE_INCLUDE_DIRS CACHE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_HALIDE)
|
||||
include_directories(${HALIDE_INCLUDE_DIRS})
|
||||
if(HALIDE_INCLUDE_DIRS)
|
||||
include_directories(${HALIDE_INCLUDE_DIRS})
|
||||
endif()
|
||||
list(APPEND OPENCV_LINKER_LIBS ${HALIDE_LIBRARIES})
|
||||
else()
|
||||
ocv_clear_vars(HALIDE_INCLUDE_DIRS HALIDE_LIBRARIES)
|
||||
endif()
|
||||
|
||||
@@ -134,12 +134,21 @@ endif()
|
||||
# Add more features to the target
|
||||
|
||||
if(INF_ENGINE_TARGET)
|
||||
if(NOT INF_ENGINE_RELEASE)
|
||||
message(WARNING "InferenceEngine version has not been set, 2021.2 will be used by default. Set INF_ENGINE_RELEASE variable if you experience build errors.")
|
||||
if(DEFINED InferenceEngine_VERSION)
|
||||
message(STATUS "InferenceEngine: ${InferenceEngine_VERSION}")
|
||||
if(NOT INF_ENGINE_RELEASE AND NOT (InferenceEngine_VERSION VERSION_LESS "2021.4"))
|
||||
math(EXPR INF_ENGINE_RELEASE_INIT "${InferenceEngine_VERSION_MAJOR} * 1000000 + ${InferenceEngine_VERSION_MINOR} * 10000 + ${InferenceEngine_VERSION_PATCH} * 100")
|
||||
endif()
|
||||
endif()
|
||||
set(INF_ENGINE_RELEASE "2021020000" CACHE STRING "Force IE version, should be in form YYYYAABBCC (e.g. 2020.1.0.2 -> 2020010002)")
|
||||
if(NOT INF_ENGINE_RELEASE AND NOT INF_ENGINE_RELEASE_INIT)
|
||||
message(WARNING "InferenceEngine version has not been set, 2021.4 will be used by default. Set INF_ENGINE_RELEASE variable if you experience build errors.")
|
||||
set(INF_ENGINE_RELEASE_INIT "2021040000")
|
||||
elseif(DEFINED INF_ENGINE_RELEASE)
|
||||
set(INF_ENGINE_RELEASE_INIT "${INF_ENGINE_RELEASE}")
|
||||
endif()
|
||||
set(INF_ENGINE_RELEASE "${INF_ENGINE_RELEASE_INIT}" CACHE STRING "Force IE version, should be in form YYYYAABBCC (e.g. 2020.1.0.2 -> 2020010002)")
|
||||
set_target_properties(${INF_ENGINE_TARGET} PROPERTIES
|
||||
INTERFACE_COMPILE_DEFINITIONS "HAVE_INF_ENGINE=1;INF_ENGINE_RELEASE=${INF_ENGINE_RELEASE}"
|
||||
INTERFACE_COMPILE_DEFINITIONS "HAVE_INF_ENGINE=1;INF_ENGINE_RELEASE=${INF_ENGINE_RELEASE}"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ 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 ...)")
|
||||
set(OPENCV_DOWNLOAD_PARAMS INACTIVITY_TIMEOUT 60 TIMEOUT 600 CACHE STRING "Download parameters to be passed to file(DOWNLOAD ...)")
|
||||
mark_as_advanced(OPENCV_DOWNLOAD_TRIES_LIST OPENCV_DOWNLOAD_PARAMS)
|
||||
|
||||
# Init download cache directory and log file and helper scripts
|
||||
|
||||
@@ -143,10 +143,25 @@ macro(ipp_detect_version)
|
||||
list(APPEND IPP_LIBRARIES ${IPP_LIBRARY_DIR}/${IPP_LIB_PREFIX}${IPP_PREFIX}${name}${IPP_SUFFIX}${IPP_LIB_SUFFIX})
|
||||
else ()
|
||||
add_library(ipp${name} STATIC IMPORTED)
|
||||
set(_filename "${IPP_LIB_PREFIX}${IPP_PREFIX}${name}${IPP_SUFFIX}${IPP_LIB_SUFFIX}")
|
||||
set_target_properties(ipp${name} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LIBRARIES ""
|
||||
IMPORTED_LOCATION ${IPP_LIBRARY_DIR}/${IPP_LIB_PREFIX}${IPP_PREFIX}${name}${IPP_SUFFIX}${IPP_LIB_SUFFIX}
|
||||
IMPORTED_LOCATION ${IPP_LIBRARY_DIR}/${_filename}
|
||||
)
|
||||
if("${name}" STREQUAL "core") # https://github.com/opencv/opencv/pull/19681
|
||||
if(OPENCV_FORCE_IPP_EXCLUDE_LIBS OR OPENCV_FORCE_IPP_EXCLUDE_LIBS_CORE
|
||||
OR (UNIX AND NOT ANDROID AND NOT APPLE
|
||||
AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|Intel"
|
||||
)
|
||||
AND NOT OPENCV_SKIP_IPP_EXCLUDE_LIBS_CORE
|
||||
)
|
||||
if(CMAKE_VERSION VERSION_LESS "3.13.0")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--exclude-libs,${_filename} ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
else()
|
||||
target_link_options(ipp${name} INTERFACE "LINKER:--exclude-libs,${_filename}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND IPP_LIBRARIES ipp${name})
|
||||
if (NOT BUILD_SHARED_LIBS AND (HAVE_IPP_ICV OR ";${OPENCV_INSTALL_EXTERNAL_DEPENDENCIES};" MATCHES ";ipp;"))
|
||||
# CMake doesn't support "install(TARGETS ${IPP_PREFIX}${name} " command with imported targets
|
||||
|
||||
@@ -2,16 +2,7 @@
|
||||
# Detect 3rd-party GUI libraries
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
#--- Win32 UI ---
|
||||
ocv_clear_vars(HAVE_WIN32UI)
|
||||
if(WITH_WIN32UI)
|
||||
try_compile(HAVE_WIN32UI
|
||||
"${OpenCV_BINARY_DIR}"
|
||||
"${OpenCV_SOURCE_DIR}/cmake/checks/win32uitest.cpp"
|
||||
CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=user32;gdi32")
|
||||
endif()
|
||||
|
||||
# --- QT4 ---
|
||||
# --- QT4/5 ---
|
||||
ocv_clear_vars(HAVE_QT HAVE_QT5)
|
||||
if(WITH_QT)
|
||||
if(NOT WITH_QT EQUAL 4)
|
||||
@@ -34,41 +25,6 @@ if(WITH_QT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- GTK ---
|
||||
ocv_clear_vars(HAVE_GTK HAVE_GTK3 HAVE_GTHREAD HAVE_GTKGLEXT)
|
||||
if(WITH_GTK AND NOT HAVE_QT)
|
||||
if(NOT WITH_GTK_2_X)
|
||||
ocv_check_modules(GTK3 gtk+-3.0)
|
||||
if(HAVE_GTK3)
|
||||
ocv_append_build_options(HIGHGUI GTK3)
|
||||
set(HAVE_GTK TRUE)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT HAVE_GTK)
|
||||
ocv_check_modules(GTK2 gtk+-2.0)
|
||||
if(HAVE_GTK2)
|
||||
if (GTK2_VERSION VERSION_LESS MIN_VER_GTK)
|
||||
message (FATAL_ERROR "GTK support requires a minimum version of ${MIN_VER_GTK} (${GTK2_VERSION} found)")
|
||||
else()
|
||||
ocv_append_build_options(HIGHGUI GTK2)
|
||||
set(HAVE_GTK TRUE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
ocv_check_modules(GTHREAD gthread-2.0)
|
||||
if(HAVE_GTK AND NOT HAVE_GTHREAD)
|
||||
message(FATAL_ERROR "gthread not found. This library is required when building with GTK support")
|
||||
else()
|
||||
ocv_append_build_options(HIGHGUI GTHREAD)
|
||||
endif()
|
||||
if(WITH_OPENGL AND NOT HAVE_GTK3)
|
||||
ocv_check_modules(GTKGLEXT gtkglext-1.0)
|
||||
if(HAVE_GTKGLEXT)
|
||||
ocv_append_build_options(HIGHGUI GTKGLEXT)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- OpenGl ---
|
||||
ocv_clear_vars(HAVE_OPENGL HAVE_QT_OPENGL)
|
||||
if(WITH_OPENGL)
|
||||
|
||||
@@ -29,7 +29,7 @@ if(WITH_IPP)
|
||||
if(OPENCV_FORCE_IPP_EXCLUDE_LIBS
|
||||
OR (HAVE_IPP_ICV
|
||||
AND UNIX AND NOT ANDROID AND NOT APPLE
|
||||
AND (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|Intel"
|
||||
)
|
||||
AND NOT OPENCV_SKIP_IPP_EXCLUDE_LIBS
|
||||
)
|
||||
|
||||
@@ -9,6 +9,14 @@
|
||||
# OPENEXR_LIBRARIES = libraries that are needed to use OpenEXR.
|
||||
#
|
||||
|
||||
find_package(OpenEXR 3.0 CONFIG QUIET)
|
||||
if(TARGET OpenEXR::OpenEXR)
|
||||
SET(OPENEXR_FOUND TRUE)
|
||||
SET(OPENEXR_LIBRARIES OpenEXR::OpenEXR)
|
||||
SET(OPENEXR_VERSION ${OpenEXR_VERSION})
|
||||
return()
|
||||
endif()
|
||||
|
||||
SET(OPENEXR_LIBRARIES "")
|
||||
SET(OPENEXR_LIBSEARCH_SUFFIXES "")
|
||||
file(TO_CMAKE_PATH "$ENV{ProgramFiles}" ProgramFiles_ENV_PATH)
|
||||
|
||||
@@ -6,4 +6,3 @@ set(MIN_VER_CUDNN 7.5)
|
||||
set(MIN_VER_PYTHON2 2.7)
|
||||
set(MIN_VER_PYTHON3 3.2)
|
||||
set(MIN_VER_ZLIB 1.2.3)
|
||||
set(MIN_VER_GTK 2.18.0)
|
||||
|
||||
@@ -879,7 +879,11 @@ endmacro()
|
||||
macro(_ocv_create_module)
|
||||
|
||||
ocv_compiler_optimization_process_sources(OPENCV_MODULE_${the_module}_SOURCES OPENCV_MODULE_${the_module}_DEPS_EXT ${the_module})
|
||||
set(OPENCV_MODULE_${the_module}_HEADERS ${OPENCV_MODULE_${the_module}_HEADERS} CACHE INTERNAL "List of header files for ${the_module}")
|
||||
set(__module_headers ${OPENCV_MODULE_${the_module}_HEADERS})
|
||||
if(__module_headers)
|
||||
list(SORT __module_headers) # fix headers order, useful for bindings
|
||||
endif()
|
||||
set(OPENCV_MODULE_${the_module}_HEADERS ${__module_headers} CACHE INTERNAL "List of header files for ${the_module}")
|
||||
set(OPENCV_MODULE_${the_module}_SOURCES ${OPENCV_MODULE_${the_module}_SOURCES} CACHE INTERNAL "List of source files for ${the_module}")
|
||||
|
||||
# The condition we ought to be testing here is whether ocv_add_precompiled_headers will
|
||||
@@ -1179,6 +1183,9 @@ function(ocv_add_perf_tests)
|
||||
if(TARGET opencv_videoio_plugins)
|
||||
add_dependencies(${the_target} opencv_videoio_plugins)
|
||||
endif()
|
||||
if(TARGET opencv_highgui_plugins)
|
||||
add_dependencies(${the_target} opencv_highgui_plugins)
|
||||
endif()
|
||||
|
||||
if(HAVE_HPX)
|
||||
message("Linking HPX to Perf test of module ${name}")
|
||||
@@ -1274,6 +1281,9 @@ function(ocv_add_accuracy_tests)
|
||||
if(TARGET opencv_videoio_plugins)
|
||||
add_dependencies(${the_target} opencv_videoio_plugins)
|
||||
endif()
|
||||
if(TARGET opencv_highgui_plugins)
|
||||
add_dependencies(${the_target} opencv_highgui_plugins)
|
||||
endif()
|
||||
|
||||
if(HAVE_HPX)
|
||||
message("Linking HPX to Perf test of module ${name}")
|
||||
@@ -1364,6 +1374,9 @@ function(ocv_add_samples)
|
||||
if(TARGET opencv_videoio_plugins)
|
||||
add_dependencies(${the_target} opencv_videoio_plugins)
|
||||
endif()
|
||||
if(TARGET opencv_highgui_plugins)
|
||||
add_dependencies(${the_target} opencv_highgui_plugins)
|
||||
endif()
|
||||
|
||||
if(INSTALL_BIN_EXAMPLES)
|
||||
install(TARGETS ${the_target} RUNTIME DESTINATION "${OPENCV_SAMPLES_BIN_INSTALL_PATH}/${module_id}" COMPONENT samples)
|
||||
|
||||
@@ -122,7 +122,6 @@ function(ocv_pylint_finalize)
|
||||
|
||||
list(LENGTH PYLINT_TARGET_ID __total)
|
||||
set(PYLINT_TOTAL_TARGETS "${__total}" CACHE INTERNAL "")
|
||||
message(STATUS "Pylint: registered ${__total} targets. Build 'check_pylint' target to run checks (\"cmake --build . --target check_pylint\" or \"make check_pylint\")")
|
||||
configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/pylint.cmake.in" "${CMAKE_BINARY_DIR}/pylint.cmake" @ONLY)
|
||||
|
||||
add_custom_target(check_pylint
|
||||
|
||||
+34
-15
@@ -866,7 +866,9 @@ macro(ocv_check_modules define)
|
||||
foreach(flag ${${define}_LDFLAGS})
|
||||
if(flag MATCHES "^-L(.*)")
|
||||
list(APPEND _libs_paths ${CMAKE_MATCH_1})
|
||||
elseif(IS_ABSOLUTE "${flag}")
|
||||
elseif(IS_ABSOLUTE "${flag}"
|
||||
OR flag STREQUAL "-lstdc++"
|
||||
)
|
||||
list(APPEND _libs "${flag}")
|
||||
elseif(flag MATCHES "^-l(.*)")
|
||||
set(_lib "${CMAKE_MATCH_1}")
|
||||
@@ -1578,24 +1580,41 @@ endfunction()
|
||||
|
||||
|
||||
function(ocv_add_external_target name inc link def)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
if(BUILD_SHARED_LIBS AND link)
|
||||
set(imp IMPORTED)
|
||||
endif()
|
||||
add_library(ocv.3rdparty.${name} INTERFACE ${imp})
|
||||
set_target_properties(ocv.3rdparty.${name} PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${inc}"
|
||||
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${inc}"
|
||||
INTERFACE_COMPILE_DEFINITIONS "${def}")
|
||||
# When cmake version is greater than or equal to 3.11, INTERFACE_LINK_LIBRARIES no longer applies to interface library
|
||||
# See https://github.com/opencv/opencv/pull/18658
|
||||
if (CMAKE_VERSION VERSION_LESS 3.11)
|
||||
set_target_properties(ocv.3rdparty.${name} PROPERTIES
|
||||
INTERFACE_LINK_LIBRARIES "${link}")
|
||||
else()
|
||||
target_link_libraries(ocv.3rdparty.${name} INTERFACE ${link})
|
||||
if(def)
|
||||
if(NOT (CMAKE_VERSION VERSION_LESS "3.11.0")) # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/1264 : eliminates "Cannot specify compile definitions for imported target" error message
|
||||
target_compile_definitions(ocv.3rdparty.${name} INTERFACE "${def}")
|
||||
else()
|
||||
set_target_properties(ocv.3rdparty.${name} PROPERTIES INTERFACE_COMPILE_DEFINITIONS "${def}")
|
||||
endif()
|
||||
endif()
|
||||
#
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
if(inc)
|
||||
if(NOT (CMAKE_VERSION VERSION_LESS "3.11.0")) # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/1264 : eliminates "Cannot specify compile definitions for imported target" error message
|
||||
target_include_directories(ocv.3rdparty.${name} SYSTEM INTERFACE "$<BUILD_INTERFACE:${inc}>")
|
||||
else()
|
||||
set_target_properties(ocv.3rdparty.${name} PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${inc}>"
|
||||
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${inc}>"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
if(link)
|
||||
# When cmake version is greater than or equal to 3.11, INTERFACE_LINK_LIBRARIES no longer applies to interface library
|
||||
# See https://github.com/opencv/opencv/pull/18658
|
||||
if(CMAKE_VERSION VERSION_LESS 3.11)
|
||||
set_target_properties(ocv.3rdparty.${name} PROPERTIES
|
||||
INTERFACE_LINK_LIBRARIES "${link}")
|
||||
else()
|
||||
target_link_libraries(ocv.3rdparty.${name} INTERFACE ${link})
|
||||
endif()
|
||||
endif()
|
||||
# to install used target only upgrade CMake
|
||||
if(NOT BUILD_SHARED_LIBS
|
||||
AND CMAKE_VERSION VERSION_LESS "3.13.0" # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/2152
|
||||
)
|
||||
install(TARGETS ocv.3rdparty.${name} EXPORT OpenCVModules)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
set(ANDROID_GRADLE_PLUGIN_VERSION "3.2.1" CACHE STRING "Android Gradle Plugin version")
|
||||
message(STATUS "Android Gradle Plugin version: ${ANDROID_GRADLE_PLUGIN_VERSION}")
|
||||
|
||||
set(KOTLIN_PLUGIN_VERSION "1.4.10" CACHE STRING "Kotlin Plugin version")
|
||||
message(STATUS "kotlin Plugin version: ${KOTLIN_GRADLE_PLUGIN_VERSION}")
|
||||
|
||||
if(BUILD_KOTLIN_EXTENSIONS)
|
||||
set(KOTLIN_PLUGIN_DECLARATION "apply plugin: 'kotlin-android'" CACHE STRING "Kotlin Plugin version")
|
||||
set(KOTLIN_STD_LIB "implementation 'org.jetbrains.kotlin:kotlin-stdlib:${KOTLIN_PLUGIN_VERSION}'" CACHE STRING "Kotlin Standard Library dependency")
|
||||
else()
|
||||
set(KOTLIN_PLUGIN_DECLARATION "" CACHE STRING "Kotlin Plugin version")
|
||||
set(KOTLIN_STD_LIB "" CACHE STRING "Kotlin Standard Library dependency")
|
||||
endif()
|
||||
|
||||
set(GRADLE_VERSION "5.6.4" CACHE STRING "Gradle version")
|
||||
message(STATUS "Gradle version: ${GRADLE_VERSION}")
|
||||
|
||||
|
||||
@@ -28,9 +28,6 @@
|
||||
/* Clp support */
|
||||
#cmakedefine HAVE_CLP
|
||||
|
||||
/* Cocoa API */
|
||||
#cmakedefine HAVE_COCOA
|
||||
|
||||
/* NVIDIA CUDA Runtime API*/
|
||||
#cmakedefine HAVE_CUDA
|
||||
|
||||
@@ -56,12 +53,6 @@
|
||||
/* Geospatial Data Abstraction Library */
|
||||
#cmakedefine HAVE_GDAL
|
||||
|
||||
/* GTK+ 2.0 Thread support */
|
||||
#cmakedefine HAVE_GTHREAD
|
||||
|
||||
/* GTK+ 2.x toolkit */
|
||||
#cmakedefine HAVE_GTK
|
||||
|
||||
/* Halide support */
|
||||
#cmakedefine HAVE_HALIDE
|
||||
|
||||
@@ -121,12 +112,6 @@
|
||||
/* parallel_for with pthreads */
|
||||
#cmakedefine HAVE_PTHREADS_PF
|
||||
|
||||
/* Qt support */
|
||||
#cmakedefine HAVE_QT
|
||||
|
||||
/* Qt OpenGL support */
|
||||
#cmakedefine HAVE_QT_OPENGL
|
||||
|
||||
/* Intel Threading Building Blocks */
|
||||
#cmakedefine HAVE_TBB
|
||||
|
||||
@@ -136,9 +121,6 @@
|
||||
/* TIFF codec */
|
||||
#cmakedefine HAVE_TIFF
|
||||
|
||||
/* Win32 UI */
|
||||
#cmakedefine HAVE_WIN32UI
|
||||
|
||||
/* Define if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
#cmakedefine WORDS_BIGENDIAN
|
||||
|
||||
+8
-2
@@ -31,7 +31,7 @@ MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 4
|
||||
ALIASES += add_toggle{1}="@htmlonly[block] <div class='newInnerHTML'>\1</div><div> <script type="text/javascript"> addToggle(); </script>@endhtmlonly"
|
||||
ALIASES += add_toggle{1}="@htmlonly[block] <div class='newInnerHTML'>\1</div><div> <script type='text/javascript'> addToggle(); </script>@endhtmlonly"
|
||||
ALIASES += add_toggle_cpp="@htmlonly[block] <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'>@endhtmlonly"
|
||||
ALIASES += add_toggle_java="@htmlonly[block] <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'>@endhtmlonly"
|
||||
ALIASES += add_toggle_python="@htmlonly[block] <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'>@endhtmlonly"
|
||||
@@ -106,7 +106,7 @@ RECURSIVE = YES
|
||||
EXCLUDE = @CMAKE_DOXYGEN_EXCLUDE_LIST@
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS = *.inl.hpp *.impl.hpp *_detail.hpp */cudev/**/detail/*.hpp *.m */opencl/runtime/* */legacy/* *_c.h @DOXYGEN_EXCLUDE_PATTERNS@
|
||||
EXCLUDE_SYMBOLS = cv::DataType<*> cv::traits::* int void CV__* T __CV*
|
||||
EXCLUDE_SYMBOLS = cv::DataType<*> cv::traits::* int void CV__* T __CV* cv::gapi::detail*
|
||||
EXAMPLE_PATH = @CMAKE_DOXYGEN_EXAMPLE_PATH@
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = YES
|
||||
@@ -255,6 +255,12 @@ PREDEFINED = __cplusplus=1 \
|
||||
CV_DEFAULT(x)=" = x" \
|
||||
CV_NEON=1 \
|
||||
CV_SSE2=1 \
|
||||
CV_SIMD128=1 \
|
||||
CV_SIMD256=1 \
|
||||
CV_SIMD512=1 \
|
||||
CV_SIMD128_64F=1 \
|
||||
CV_SIMD256_64F=1 \
|
||||
CV_SIMD512_64F=1 \
|
||||
CV__DEBUG_NS_BEGIN= \
|
||||
CV__DEBUG_NS_END= \
|
||||
CV_DEPRECATED_EXTERNAL= \
|
||||
|
||||
@@ -145,6 +145,7 @@ Building OpenCV.js from Source
|
||||
python ./platforms/js/build_js.py build_js --cmake_option="-DOPENCV_EXTRA_MODULES_PATH=opencv_contrib/modules"
|
||||
@endcode
|
||||
|
||||
|
||||
Running OpenCV.js Tests
|
||||
---------------------------------------
|
||||
|
||||
@@ -310,6 +311,12 @@ The example uses latest version of emscripten. If the build fails you should try
|
||||
docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk:2.0.10 emcmake python3 ./platforms/js/build_js.py build_js
|
||||
@endcode
|
||||
|
||||
In Windows use the following PowerShell command:
|
||||
|
||||
@code{.bash}
|
||||
docker run --rm --workdir /src -v "$(get-location):/src" "emscripten/emsdk:2.0.10" emcmake python3 ./platforms/js/build_js.py build_js
|
||||
@endcode
|
||||
|
||||
### Building the documentation with Docker
|
||||
|
||||
To build the documentation `doxygen` needs to be installed. Create a file named `Dockerfile` with the following content:
|
||||
|
||||
+14
-4
@@ -850,12 +850,12 @@
|
||||
journal = {IEEE Transactions on Robotics and Automation},
|
||||
title = {Robot sensor calibration: solving AX=XB on the Euclidean group},
|
||||
year = {1994},
|
||||
month = oct,
|
||||
volume = {10},
|
||||
number = {5},
|
||||
pages = {717-721},
|
||||
doi = {10.1109/70.326576},
|
||||
ISSN = {1042-296X},
|
||||
month = {Oct}
|
||||
issn = {1042-296X}
|
||||
}
|
||||
@inproceedings{PM03,
|
||||
author = {P{\'e}rez, Patrick and Gangnet, Michel and Blake, Andrew},
|
||||
@@ -1051,12 +1051,12 @@
|
||||
journal = {IEEE Transactions on Robotics and Automation},
|
||||
title = {A new technique for fully autonomous and efficient 3D robotics hand/eye calibration},
|
||||
year = {1989},
|
||||
month = jun,
|
||||
volume = {5},
|
||||
number = {3},
|
||||
pages = {345-358},
|
||||
doi = {10.1109/70.34770},
|
||||
ISSN = {1042-296X},
|
||||
month = {June}
|
||||
issn = {1042-296X}
|
||||
}
|
||||
@inproceedings{UES01,
|
||||
author = {Uyttendaele, Matthew and Eden, Ashley and Skeliski, R},
|
||||
@@ -1324,3 +1324,13 @@
|
||||
pages={5551--5560},
|
||||
year={2017}
|
||||
}
|
||||
@article{umeyama1991least,
|
||||
title={Least-squares estimation of transformation parameters between two point patterns},
|
||||
author={Umeyama, Shinji},
|
||||
journal={IEEE Computer Architecture Letters},
|
||||
volume={13},
|
||||
number={04},
|
||||
pages={376--380},
|
||||
year={1991},
|
||||
publisher={IEEE Computer Society}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,12 @@ using **cv.Sobel()**).
|
||||
Then comes the main part. After this, they created a score, basically an equation, which
|
||||
determines if a window can contain a corner or not.
|
||||
|
||||
\f[R = det(M) - k(trace(M))^2\f]
|
||||
\f[R = \det(M) - k(\operatorname{trace}(M))^2\f]
|
||||
|
||||
where
|
||||
- \f$det(M) = \lambda_1 \lambda_2\f$
|
||||
- \f$trace(M) = \lambda_1 + \lambda_2\f$
|
||||
- \f$\lambda_1\f$ and \f$\lambda_2\f$ are the eigenvalues of M
|
||||
- \f$\det(M) = \lambda_1 \lambda_2\f$
|
||||
- \f$\operatorname{trace}(M) = \lambda_1 + \lambda_2\f$
|
||||
- \f$\lambda_1\f$ and \f$\lambda_2\f$ are the eigenvalues of \f$M\f$
|
||||
|
||||
So the magnitudes of these eigenvalues decide whether a region is a corner, an edge, or flat.
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Harris Corner Detector. The scoring function in Harris Corner Detector was given
|
||||
|
||||
Instead of this, Shi-Tomasi proposed:
|
||||
|
||||
\f[R = min(\lambda_1, \lambda_2)\f]
|
||||
\f[R = \min(\lambda_1, \lambda_2)\f]
|
||||
|
||||
If it is a greater than a threshold value, it is considered as a corner. If we plot it in
|
||||
\f$\lambda_1 - \lambda_2\f$ space as we did in Harris Corner Detector, we get an image as below:
|
||||
@@ -28,7 +28,7 @@ If it is a greater than a threshold value, it is considered as a corner. If we p
|
||||

|
||||
|
||||
From the figure, you can see that only when \f$\lambda_1\f$ and \f$\lambda_2\f$ are above a minimum value,
|
||||
\f$\lambda_{min}\f$, it is considered as a corner(green region).
|
||||
\f$\lambda_{\min}\f$, it is considered as a corner(green region).
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
@@ -156,7 +156,7 @@ sift = cv.SIFT_create()
|
||||
kp, des = sift.detectAndCompute(gray,None)
|
||||
@endcode
|
||||
Here kp will be a list of keypoints and des is a numpy array of shape
|
||||
\f$Number\_of\_Keypoints \times 128\f$.
|
||||
\f$\text{(Number of Keypoints)} \times 128\f$.
|
||||
|
||||
So we got keypoints, descriptors etc. Now we want to see how to match keypoints in different images.
|
||||
That we will learn in coming chapters.
|
||||
|
||||
@@ -107,17 +107,10 @@ def add_signature_to_table(soup, table, signature, language, type):
|
||||
""" Add a signature to an html table"""
|
||||
row = soup.new_tag('tr')
|
||||
row.append(soup.new_tag('td', style='width: 20px;'))
|
||||
|
||||
if 'ret' in signature:
|
||||
row.append(append(soup.new_tag('td'), signature['ret']))
|
||||
row.append(append(soup.new_tag('td'), '='))
|
||||
else:
|
||||
row.append(soup.new_tag('td')) # return values
|
||||
row.append(soup.new_tag('td')) # '='
|
||||
|
||||
row.append(append(soup.new_tag('td'), signature['name'] + '('))
|
||||
row.append(append(soup.new_tag('td', **{'class': 'paramname'}), signature['arg']))
|
||||
row.append(append(soup.new_tag('td'), ')'))
|
||||
row.append(append(soup.new_tag('td'), ') -> '))
|
||||
row.append(append(soup.new_tag('td'), signature['ret']))
|
||||
table.append(row)
|
||||
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ extension, its first version. A direct limitation of this is that you cannot sav
|
||||
larger than 2 GB. Furthermore you can only create and expand a single video track inside the
|
||||
container. No audio or other track editing support here. Nevertheless, any video codec present on
|
||||
your system might work. If you encounter some of these limitations you will need to look into more
|
||||
specialized video writing libraries such as *FFMpeg* or codecs as *HuffYUV*, *CorePNG* and *LCL*. As
|
||||
specialized video writing libraries such as *FFmpeg* or codecs as *HuffYUV*, *CorePNG* and *LCL*. As
|
||||
an alternative, create the video track with OpenCV and expand it with sound tracks or convert it to
|
||||
other formats by using video manipulation programs such as *VirtualDub* or *AviSynth*.
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ The tutorial consists of two main programs:
|
||||
|
||||
The application starts up extracting the ORB features and descriptors from the input image and
|
||||
then uses the mesh along with the [Möller–Trumbore intersection
|
||||
algorithm](http://http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm/)
|
||||
algorithm](http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm/)
|
||||
to compute the 3D coordinates of the found features. Finally, the 3D points and the descriptors
|
||||
are stored in different lists in a file with YAML format which each row is a different point. The
|
||||
technical background on how to store the files can be found in the @ref tutorial_file_input_output_with_xml_yml
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,140 @@
|
||||
# Conversion of TensorFlow Detection Models and Launch with OpenCV Python {#tf_det_tutorial_dnn_conversion}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Anastasia Murzova |
|
||||
| Compatibility | OpenCV >= 4.5 |
|
||||
|
||||
## Goals
|
||||
In this tutorial you will learn how to:
|
||||
* obtain frozen graphs of TensorFlow (TF) detection models
|
||||
* run converted TensorFlow model with OpenCV Python API
|
||||
|
||||
We will explore the above-listed points by the example of SSD MobileNetV1.
|
||||
|
||||
## Introduction
|
||||
Let's briefly view the key concepts involved in the pipeline of TensorFlow models transition with OpenCV API. The initial step in the conversion of TensorFlow models into cv.dnn.Net
|
||||
is obtaining the frozen TF model graph. A frozen graph defines the combination of the model graph structure with kept values of the required variables, for example, weights. The frozen graph is saved in [protobuf](https://en.wikipedia.org/wiki/Protocol_Buffers) (```.pb```) files.
|
||||
There are special functions for reading ``.pb`` graphs in OpenCV: cv.dnn.readNetFromTensorflow and cv.dnn.readNet.
|
||||
|
||||
## Requirements
|
||||
To be able to experiment with the below code you will need to install a set of libraries. We will use a virtual environment with python3.7+ for this:
|
||||
|
||||
```console
|
||||
virtualenv -p /usr/bin/python3.7 <env_dir_path>
|
||||
source <env_dir_path>/bin/activate
|
||||
```
|
||||
|
||||
For OpenCV-Python building from source, follow the corresponding instructions from the @ref tutorial_py_table_of_contents_setup.
|
||||
|
||||
Before you start the installation of the libraries, you can customize the [requirements.txt](https://github.com/opencv/opencv/tree/master/samples/dnn/dnn_model_runner/dnn_conversion/requirements.txt), excluding or including (for example, ``opencv-python``) some dependencies.
|
||||
The below line initiates requirements installation into the previously activated virtual environment:
|
||||
|
||||
```console
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Practice
|
||||
In this part we are going to cover the following points:
|
||||
1. create a TF classification model conversion pipeline and provide the inference
|
||||
2. provide the inference, process prediction results
|
||||
|
||||
### Model Preparation
|
||||
The code in this subchapter is located in the ``samples/dnn/dnn_model_runner`` module and can be executed with the below line:
|
||||
|
||||
```console
|
||||
python -m dnn_model_runner.dnn_conversion.tf.detection.py_to_py_ssd_mobilenet
|
||||
```
|
||||
|
||||
The following code contains the steps of the TF SSD MobileNetV1 model retrieval:
|
||||
|
||||
```python
|
||||
tf_model_name = 'ssd_mobilenet_v1_coco_2017_11_17'
|
||||
graph_extraction_dir = "./"
|
||||
frozen_graph_path = extract_tf_frozen_graph(tf_model_name, graph_extraction_dir)
|
||||
print("Frozen graph path for {}: {}".format(tf_model_name, frozen_graph_path))
|
||||
```
|
||||
|
||||
In ``extract_tf_frozen_graph`` function we extract the provided in model archive ``frozen_inference_graph.pb`` for its further processing:
|
||||
|
||||
```python
|
||||
# define model archive name
|
||||
tf_model_tar = model_name + '.tar.gz'
|
||||
# define link to retrieve model archive
|
||||
model_link = DETECTION_MODELS_URL + tf_model_tar
|
||||
|
||||
tf_frozen_graph_name = 'frozen_inference_graph'
|
||||
|
||||
try:
|
||||
urllib.request.urlretrieve(model_link, tf_model_tar)
|
||||
except Exception:
|
||||
print("TF {} was not retrieved: {}".format(model_name, model_link))
|
||||
return
|
||||
|
||||
print("TF {} was retrieved.".format(model_name))
|
||||
|
||||
tf_model_tar = tarfile.open(tf_model_tar)
|
||||
frozen_graph_path = ""
|
||||
|
||||
for model_tar_elem in tf_model_tar.getmembers():
|
||||
if tf_frozen_graph_name in os.path.basename(model_tar_elem.name):
|
||||
tf_model_tar.extract(model_tar_elem, extracted_model_path)
|
||||
frozen_graph_path = os.path.join(extracted_model_path, model_tar_elem.name)
|
||||
break
|
||||
tf_model_tar.close()
|
||||
```
|
||||
|
||||
After the successful execution of the above code we will get the following output:
|
||||
|
||||
```console
|
||||
TF ssd_mobilenet_v1_coco_2017_11_17 was retrieved.
|
||||
Frozen graph path for ssd_mobilenet_v1_coco_2017_11_17: ./ssd_mobilenet_v1_coco_2017_11_17/frozen_inference_graph.pb
|
||||
```
|
||||
|
||||
To provide model inference we will use the below [double-decker bus photo](https://www.pexels.com/photo/bus-and-car-on-one-way-street-3626589/) (under [Pexels](https://www.pexels.com/license/) license):
|
||||
|
||||

|
||||
|
||||
To initiate the test process we need to provide an appropriate model configuration. We will use [``ssd_mobilenet_v1_coco.config``](https://github.com/tensorflow/models/blob/master/research/object_detection/samples/configs/ssd_mobilenet_v1_coco.config) from [TensorFlow Object Detection API](https://github.com/tensorflow/models/tree/master/research/object_detection#tensorflow-object-detection-api).
|
||||
TensorFlow Object Detection API framework contains helpful mechanisms for object detection model manipulations.
|
||||
|
||||
We will use this configuration to provide a text graph representation. To generate ``.pbtxt`` we will use the corresponding [``samples/dnn/tf_text_graph_ssd.py``](https://github.com/opencv/opencv/blob/master/samples/dnn/tf_text_graph_ssd.py) script:
|
||||
|
||||
```console
|
||||
python tf_text_graph_ssd.py --input ssd_mobilenet_v1_coco_2017_11_17/frozen_inference_graph.pb --config ssd_mobilenet_v1_coco_2017_11_17/ssd_mobilenet_v1_coco.config --output ssd_mobilenet_v1_coco_2017_11_17.pbtxt
|
||||
```
|
||||
|
||||
After successful execution ``ssd_mobilenet_v1_coco_2017_11_17.pbtxt`` will be created.
|
||||
|
||||
Before we run ``object_detection.py``, let's have a look at the default values for the SSD MobileNetV1 test process configuration. They are located in [``models.yml``](https://github.com/opencv/opencv/blob/master/samples/dnn/models.yml):
|
||||
|
||||
```yml
|
||||
ssd_tf:
|
||||
model: "ssd_mobilenet_v1_coco_2017_11_17.pb"
|
||||
config: "ssd_mobilenet_v1_coco_2017_11_17.pbtxt"
|
||||
mean: [0, 0, 0]
|
||||
scale: 1.0
|
||||
width: 300
|
||||
height: 300
|
||||
rgb: true
|
||||
classes: "object_detection_classes_coco.txt"
|
||||
sample: "object_detection"
|
||||
```
|
||||
|
||||
To fetch these values we need to provide frozen graph ``ssd_mobilenet_v1_coco_2017_11_17.pb`` model and text graph ``ssd_mobilenet_v1_coco_2017_11_17.pbtxt``:
|
||||
|
||||
```console
|
||||
python object_detection.py ssd_tf --input ../data/pexels_double_decker_bus.jpg
|
||||
```
|
||||
|
||||
This line is equivalent to:
|
||||
|
||||
```console
|
||||
python object_detection.py --model ssd_mobilenet_v1_coco_2017_11_17.pb --config ssd_mobilenet_v1_coco_2017_11_17.pbtxt --input ../data/pexels_double_decker_bus.jpg --width 300 --height 300 --classes ../data/dnn/object_detection_classes_coco.txt
|
||||
```
|
||||
|
||||
The result is:
|
||||
|
||||

|
||||
|
||||
There are several helpful parameters, which can be also customized for result corrections: threshold (``--thr``) and non-maximum suppression (``--nms``) values.
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
# Conversion of PyTorch Segmentation Models and Launch with OpenCV {#pytorch_segm_tutorial_dnn_conversion}
|
||||
|
||||
## Goals
|
||||
In this tutorial you will learn how to:
|
||||
* convert PyTorch segmentation models
|
||||
* run converted PyTorch model with OpenCV
|
||||
* obtain an evaluation of the PyTorch and OpenCV DNN models
|
||||
|
||||
We will explore the above-listed points by the example of the FCN ResNet-50 architecture.
|
||||
|
||||
## Introduction
|
||||
The key points involved in the transition pipeline of the [PyTorch classification](https://link_to_cls_tutorial) and segmentation models with OpenCV API are equal. The first step is model transferring into [ONNX](https://onnx.ai/about.html) format with PyTorch [``torch.onnx.export``](https://pytorch.org/docs/stable/onnx.html#torch.onnx.export) built-in function.
|
||||
Further the obtained ``.onnx`` model is passed into cv.dnn.readNetFromONNX, which returns cv.dnn.Net object ready for DNN manipulations.
|
||||
|
||||
## Practice
|
||||
In this part we are going to cover the following points:
|
||||
1. create a segmentation model conversion pipeline and provide the inference
|
||||
2. evaluate and test segmentation models
|
||||
|
||||
If you'd like merely to run evaluation or test model pipelines, the "Model Conversion Pipeline" part can be skipped.
|
||||
|
||||
### Model Conversion Pipeline
|
||||
The code in this subchapter is located in the ``dnn_model_runner`` module and can be executed with the line:
|
||||
|
||||
``
|
||||
python -m dnn_model_runner.dnn_conversion.pytorch.segmentation.py_to_py_fcnresnet50
|
||||
``
|
||||
|
||||
The following code contains the description of the below-listed steps:
|
||||
1. instantiate PyTorch model
|
||||
2. convert PyTorch model into ``.onnx``
|
||||
3. read the transferred network with OpenCV API
|
||||
4. prepare input data
|
||||
5. provide inference
|
||||
6. get colored masks from predictions
|
||||
7. visualize results
|
||||
|
||||
```python
|
||||
# initialize PyTorch FCN ResNet-50 model
|
||||
original_model = models.segmentation.fcn_resnet50(pretrained=True)
|
||||
|
||||
# get the path to the converted into ONNX PyTorch model
|
||||
full_model_path = get_pytorch_onnx_model(original_model)
|
||||
|
||||
# read converted .onnx model with OpenCV API
|
||||
opencv_net = cv2.dnn.readNetFromONNX(full_model_path)
|
||||
print("OpenCV model was successfully read. Layer IDs: \n", opencv_net.getLayerNames())
|
||||
|
||||
# get preprocessed image
|
||||
img, input_img = get_processed_imgs("test_data/sem_segm/2007_000033.jpg")
|
||||
|
||||
# obtain OpenCV DNN predictions
|
||||
opencv_prediction = get_opencv_dnn_prediction(opencv_net, input_img)
|
||||
|
||||
# obtain original PyTorch ResNet50 predictions
|
||||
pytorch_prediction = get_pytorch_dnn_prediction(original_model, input_img)
|
||||
|
||||
pascal_voc_classes, pascal_voc_colors = read_colors_info("test_data/sem_segm/pascal-classes.txt")
|
||||
|
||||
# obtain colored segmentation masks
|
||||
opencv_colored_mask = get_colored_mask(img.shape, opencv_prediction, pascal_voc_colors)
|
||||
pytorch_colored_mask = get_colored_mask(img.shape, pytorch_prediction, pascal_voc_colors)
|
||||
|
||||
# obtain palette of PASCAL VOC colors
|
||||
color_legend = get_legend(pascal_voc_classes, pascal_voc_colors)
|
||||
|
||||
cv2.imshow('PyTorch Colored Mask', pytorch_colored_mask)
|
||||
cv2.imshow('OpenCV DNN Colored Mask', opencv_colored_mask)
|
||||
cv2.imshow('Color Legend', color_legend)
|
||||
|
||||
cv2.waitKey(0)
|
||||
```
|
||||
|
||||
To provide the model inference we will use the below picture from the [PASCAL VOC](http://host.robots.ox.ac.uk/pascal/VOC/) validation dataset:
|
||||
|
||||

|
||||
|
||||
The target segmented result is:
|
||||
|
||||

|
||||
|
||||
For the PASCAL VOC colors decoding and its mapping with the predicted masks, we also need ``pascal-classes.txt`` file, which contains the full list of the PASCAL VOC classes and corresponding colors.
|
||||
|
||||
Let's go deeper into each code step by the example of pretrained PyTorch FCN ResNet-50:
|
||||
* instantiate PyTorch FCN ResNet-50 model:
|
||||
|
||||
```python
|
||||
# initialize PyTorch FCN ResNet-50 model
|
||||
original_model = models.segmentation.fcn_resnet50(pretrained=True)
|
||||
```
|
||||
|
||||
* convert PyTorch model into ONNX format:
|
||||
|
||||
```python
|
||||
# define the directory for further converted model save
|
||||
onnx_model_path = "models"
|
||||
# define the name of further converted model
|
||||
onnx_model_name = "fcnresnet50.onnx"
|
||||
|
||||
# create directory for further converted model
|
||||
os.makedirs(onnx_model_path, exist_ok=True)
|
||||
|
||||
# get full path to the converted model
|
||||
full_model_path = os.path.join(onnx_model_path, onnx_model_name)
|
||||
|
||||
# generate model input to build the graph
|
||||
generated_input = Variable(
|
||||
torch.randn(1, 3, 500, 500)
|
||||
)
|
||||
|
||||
# model export into ONNX format
|
||||
torch.onnx.export(
|
||||
original_model,
|
||||
generated_input,
|
||||
full_model_path,
|
||||
verbose=True,
|
||||
input_names=["input"],
|
||||
output_names=["output"],
|
||||
opset_version=11
|
||||
)
|
||||
```
|
||||
|
||||
The code from this step does not differ from the classification conversion case. Thus, after the successful execution of the above code, we will get ``models/fcnresnet50.onnx``.
|
||||
|
||||
* read the transferred network with cv.dnn.readNetFromONNX passing the obtained in the previous step ONNX model into it:
|
||||
|
||||
```python
|
||||
# read converted .onnx model with OpenCV API
|
||||
opencv_net = cv2.dnn.readNetFromONNX(full_model_path)
|
||||
```
|
||||
|
||||
* prepare input data:
|
||||
|
||||
```python
|
||||
# read the image
|
||||
input_img = cv2.imread(img_path, cv2.IMREAD_COLOR)
|
||||
input_img = input_img.astype(np.float32)
|
||||
|
||||
# target image sizes
|
||||
img_height = input_img.shape[0]
|
||||
img_width = input_img.shape[1]
|
||||
|
||||
# define preprocess parameters
|
||||
mean = np.array([0.485, 0.456, 0.406]) * 255.0
|
||||
scale = 1 / 255.0
|
||||
std = [0.229, 0.224, 0.225]
|
||||
|
||||
# prepare input blob to fit the model input:
|
||||
# 1. subtract mean
|
||||
# 2. scale to set pixel values from 0 to 1
|
||||
input_blob = cv2.dnn.blobFromImage(
|
||||
image=input_img,
|
||||
scalefactor=scale,
|
||||
size=(img_width, img_height), # img target size
|
||||
mean=mean,
|
||||
swapRB=True, # BGR -> RGB
|
||||
crop=False # center crop
|
||||
)
|
||||
# 3. divide by std
|
||||
input_blob[0] /= np.asarray(std, dtype=np.float32).reshape(3, 1, 1)
|
||||
```
|
||||
|
||||
In this step we read the image and prepare model input with cv2.dnn.blobFromImage function, which returns 4-dimensional blob.
|
||||
It should be noted that firstly in ``cv2.dnn.blobFromImage`` mean value is subtracted and only then pixel values are scaled. Thus, ``mean`` is multiplied by ``255.0`` to reproduce the original image preprocessing order:
|
||||
|
||||
```python
|
||||
img /= 255.0
|
||||
img -= [0.485, 0.456, 0.406]
|
||||
img /= [0.229, 0.224, 0.225]
|
||||
```
|
||||
|
||||
* OpenCV ``cv.dnn_Net`` inference:
|
||||
|
||||
```python
|
||||
# set OpenCV DNN input
|
||||
opencv_net.setInput(preproc_img)
|
||||
|
||||
# OpenCV DNN inference
|
||||
out = opencv_net.forward()
|
||||
print("OpenCV DNN segmentation prediction: \n")
|
||||
print("* shape: ", out.shape)
|
||||
|
||||
# get IDs of predicted classes
|
||||
out_predictions = np.argmax(out[0], axis=0)
|
||||
```
|
||||
|
||||
After the above code execution we will get the following output:
|
||||
|
||||
```
|
||||
OpenCV DNN segmentation prediction:
|
||||
* shape: (1, 21, 500, 500)
|
||||
```
|
||||
|
||||
Each prediction channel out of 21, where 21 represents the number of PASCAL VOC classes, contains probabilities, which indicate how likely the pixel corresponds to the PASCAL VOC class.
|
||||
|
||||
* PyTorch FCN ResNet-50 model inference:
|
||||
|
||||
```python
|
||||
original_net.eval()
|
||||
preproc_img = torch.FloatTensor(preproc_img)
|
||||
|
||||
with torch.no_grad():
|
||||
# obtaining unnormalized probabilities for each class
|
||||
out = original_net(preproc_img)['out']
|
||||
|
||||
print("\nPyTorch segmentation model prediction: \n")
|
||||
print("* shape: ", out.shape)
|
||||
|
||||
# get IDs of predicted classes
|
||||
out_predictions = out[0].argmax(dim=0)
|
||||
```
|
||||
|
||||
After the above code launching we will get the following output:
|
||||
|
||||
```
|
||||
PyTorch segmentation model prediction:
|
||||
* shape: torch.Size([1, 21, 366, 500])
|
||||
```
|
||||
|
||||
PyTorch prediction also contains probabilities corresponding to each class prediction.
|
||||
|
||||
* get colored masks from predictions:
|
||||
|
||||
```python
|
||||
# convert mask values into PASCAL VOC colors
|
||||
processed_mask = np.stack([colors[color_id] for color_id in segm_mask.flatten()])
|
||||
|
||||
# reshape mask into 3-channel image
|
||||
processed_mask = processed_mask.reshape(mask_height, mask_width, 3)
|
||||
processed_mask = cv2.resize(processed_mask, (img_width, img_height), interpolation=cv2.INTER_NEAREST).astype(
|
||||
np.uint8)
|
||||
|
||||
# convert colored mask from BGR to RGB for compatibility with PASCAL VOC colors
|
||||
processed_mask = cv2.cvtColor(processed_mask, cv2.COLOR_BGR2RGB)
|
||||
```
|
||||
|
||||
In this step we map the probabilities from segmentation masks with appropriate colors of the predicted classes. Let's have a look at the results:
|
||||
|
||||

|
||||
|
||||
For the extended evaluation of the models, we can use ``py_to_py_segm`` script of the ``dnn_model_runner`` module. This module part will be described in the next subchapter.
|
||||
|
||||
### Evaluation of the Models
|
||||
|
||||
The proposed in ``dnn/samples`` ``dnn_model_runner`` module allows to run the full evaluation pipeline on the PASCAL VOC dataset and test execution for the following PyTorch segmentation models:
|
||||
* FCN ResNet-50
|
||||
* FCN ResNet-101
|
||||
|
||||
This list can be also extended with further appropriate evaluation pipeline configuration.
|
||||
|
||||
#### Evaluation Mode
|
||||
|
||||
The below line represents running of the module in the evaluation mode:
|
||||
|
||||
```
|
||||
python -m dnn_model_runner.dnn_conversion.pytorch.segmentation.py_to_py_segm --model_name <pytorch_segm_model_name>
|
||||
```
|
||||
|
||||
Chosen from the list segmentation model will be read into OpenCV ``cv.dnn_Net`` object. Evaluation results of PyTorch and OpenCV models (pixel accuracy, mean IoU, inference time) will be written into the log file. Inference time values will be also depicted in a chart to generalize the obtained model information.
|
||||
|
||||
Necessary evaluation configurations are defined in the [``test_config.py``](https://github.com/opencv/opencv/tree/master/samples/dnn/dnn_model_runner/dnn_conversion/common/test/configs/test_config.py):
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TestSegmConfig:
|
||||
frame_size: int = 500
|
||||
img_root_dir: str = "./VOC2012"
|
||||
img_dir: str = os.path.join(img_root_dir, "JPEGImages/")
|
||||
img_segm_gt_dir: str = os.path.join(img_root_dir, "SegmentationClass/")
|
||||
# reduced val: https://github.com/shelhamer/fcn.berkeleyvision.org/blob/master/data/pascal/seg11valid.txt
|
||||
segm_val_file: str = os.path.join(img_root_dir, "ImageSets/Segmentation/seg11valid.txt")
|
||||
colour_file_cls: str = os.path.join(img_root_dir, "ImageSets/Segmentation/pascal-classes.txt")
|
||||
```
|
||||
|
||||
These values can be modified in accordance with chosen model pipeline.
|
||||
|
||||
To initiate the evaluation of the PyTorch FCN ResNet-50, run the following line:
|
||||
|
||||
```
|
||||
python -m dnn_model_runner.dnn_conversion.pytorch.segmentation.py_to_py_segm --model_name fcnresnet50
|
||||
```
|
||||
|
||||
#### Test Mode
|
||||
|
||||
The below line represents running of the module in the test mode, which provides the steps for the model inference:
|
||||
|
||||
```
|
||||
python -m dnn_model_runner.dnn_conversion.pytorch.segmentation.py_to_py_segm --model_name <pytorch_segm_model_name> --test True --default_img_preprocess <True/False> --evaluate False
|
||||
```
|
||||
|
||||
Here ``default_img_preprocess`` key defines whether you'd like to parametrize the model test process with some particular values or use the default values, for example, ``scale``, ``mean`` or ``std``.
|
||||
|
||||
Test configuration is represented in [``test_config.py``](https://github.com/opencv/opencv/tree/master/samples/dnn/dnn_model_runner/dnn_conversion/common/test/configs/test_config.py) ``TestSegmModuleConfig`` class:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TestSegmModuleConfig:
|
||||
segm_test_data_dir: str = "test_data/sem_segm"
|
||||
test_module_name: str = "segmentation"
|
||||
test_module_path: str = "segmentation.py"
|
||||
input_img: str = os.path.join(segm_test_data_dir, "2007_000033.jpg")
|
||||
model: str = ""
|
||||
|
||||
frame_height: str = str(TestSegmConfig.frame_size)
|
||||
frame_width: str = str(TestSegmConfig.frame_size)
|
||||
scale: float = 1.0
|
||||
mean: List[float] = field(default_factory=lambda: [0.0, 0.0, 0.0])
|
||||
std: List[float] = field(default_factory=list)
|
||||
crop: bool = False
|
||||
rgb: bool = True
|
||||
classes: str = os.path.join(segm_test_data_dir, "pascal-classes.txt")
|
||||
```
|
||||
|
||||
The default image preprocessing options are defined in ``default_preprocess_config.py``:
|
||||
|
||||
```python
|
||||
pytorch_segm_input_blob = {
|
||||
"mean": ["123.675", "116.28", "103.53"],
|
||||
"scale": str(1 / 255.0),
|
||||
"std": ["0.229", "0.224", "0.225"],
|
||||
"crop": "False",
|
||||
"rgb": "True"
|
||||
}
|
||||
```
|
||||
|
||||
The basis of the model testing is represented in ``samples/dnn/segmentation.py``. ``segmentation.py`` can be executed autonomously with provided converted model in ``--input`` and populated parameters for ``cv2.dnn.blobFromImage``.
|
||||
|
||||
To reproduce from scratch the described in "Model Conversion Pipeline" OpenCV steps with ``dnn_model_runner`` execute the below line:
|
||||
|
||||
```
|
||||
python -m dnn_model_runner.dnn_conversion.pytorch.segmentation.py_to_py_segm --model_name fcnresnet50 --test True --default_img_preprocess True --evaluate False
|
||||
```
|
||||
+406
@@ -0,0 +1,406 @@
|
||||
# Conversion of TensorFlow Segmentation Models and Launch with OpenCV {#tf_segm_tutorial_dnn_conversion}
|
||||
|
||||
## Goals
|
||||
In this tutorial you will learn how to:
|
||||
* convert TensorFlow (TF) segmentation models
|
||||
* run converted TensorFlow model with OpenCV
|
||||
* obtain an evaluation of the TensorFlow and OpenCV DNN models
|
||||
|
||||
We will explore the above-listed points by the example of the DeepLab architecture.
|
||||
|
||||
## Introduction
|
||||
The key concepts involved in the transition pipeline of the [TensorFlow classification](https://link_to_cls_tutorial) and segmentation models with OpenCV API are almost equal excepting the phase of graph optimization. The initial step in conversion of TensorFlow models into cv.dnn.Net
|
||||
is obtaining the frozen TF model graph. Frozen graph defines the combination of the model graph structure with kept values of the required variables, for example, weights. Usually the frozen graph is saved in [protobuf](https://en.wikipedia.org/wiki/Protocol_Buffers) (```.pb```) files.
|
||||
To read the generated segmentation model ``.pb`` file with cv.dnn.readNetFromTensorflow, it is needed to modify the graph with TF [graph transform tool](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/graph_transforms).
|
||||
|
||||
## Practice
|
||||
In this part we are going to cover the following points:
|
||||
1. create a TF classification model conversion pipeline and provide the inference
|
||||
2. evaluate and test TF classification models
|
||||
|
||||
If you'd like merely to run evaluation or test model pipelines, the "Model Conversion Pipeline" tutorial part can be skipped.
|
||||
|
||||
### Model Conversion Pipeline
|
||||
The code in this subchapter is located in the ``dnn_model_runner`` module and can be executed with the line:
|
||||
|
||||
```
|
||||
python -m dnn_model_runner.dnn_conversion.tf.segmentation.py_to_py_deeplab
|
||||
```
|
||||
|
||||
TensorFlow segmentation models can be found in [TensorFlow Research Models](https://github.com/tensorflow/models/tree/master/research/#tensorflow-research-models) section, which contains the implementations of models on the basis of published research papers.
|
||||
We will retrieve the archive with the pre-trained TF DeepLabV3 from the below link:
|
||||
|
||||
```
|
||||
http://download.tensorflow.org/models/deeplabv3_mnv2_pascal_trainval_2018_01_29.tar.gz
|
||||
```
|
||||
|
||||
The full frozen graph obtaining pipeline is described in ``deeplab_retrievement.py``:
|
||||
|
||||
```python
|
||||
def get_deeplab_frozen_graph():
|
||||
# define model path to download
|
||||
models_url = 'http://download.tensorflow.org/models/'
|
||||
mobilenetv2_voctrainval = 'deeplabv3_mnv2_pascal_trainval_2018_01_29.tar.gz'
|
||||
|
||||
# construct model link to download
|
||||
model_link = models_url + mobilenetv2_voctrainval
|
||||
|
||||
try:
|
||||
urllib.request.urlretrieve(model_link, mobilenetv2_voctrainval)
|
||||
except Exception:
|
||||
print("TF DeepLabV3 was not retrieved: {}".format(model_link))
|
||||
return
|
||||
|
||||
tf_model_tar = tarfile.open(mobilenetv2_voctrainval)
|
||||
|
||||
# iterate the obtained model archive
|
||||
for model_tar_elem in tf_model_tar.getmembers():
|
||||
# check whether the model archive contains frozen graph
|
||||
if TF_FROZEN_GRAPH_NAME in os.path.basename(model_tar_elem.name):
|
||||
# extract frozen graph
|
||||
tf_model_tar.extract(model_tar_elem, FROZEN_GRAPH_PATH)
|
||||
|
||||
tf_model_tar.close()
|
||||
```
|
||||
|
||||
After running this script:
|
||||
|
||||
```
|
||||
python -m dnn_model_runner.dnn_conversion.tf.segmentation.deeplab_retrievement
|
||||
```
|
||||
|
||||
we will get ``frozen_inference_graph.pb`` in ``deeplab/deeplabv3_mnv2_pascal_trainval``.
|
||||
|
||||
Before going to the network loading with OpenCV it is needed to optimize the extracted ``frozen_inference_graph.pb``.
|
||||
To optimize the graph we use TF ``TransformGraph`` with default parameters:
|
||||
|
||||
```python
|
||||
DEFAULT_OPT_GRAPH_NAME = "optimized_frozen_inference_graph.pb"
|
||||
DEFAULT_INPUTS = "sub_7"
|
||||
DEFAULT_OUTPUTS = "ResizeBilinear_3"
|
||||
DEFAULT_TRANSFORMS = "remove_nodes(op=Identity)" \
|
||||
" merge_duplicate_nodes" \
|
||||
" strip_unused_nodes" \
|
||||
" fold_constants(ignore_errors=true)" \
|
||||
" fold_batch_norms" \
|
||||
" fold_old_batch_norms"
|
||||
|
||||
|
||||
def optimize_tf_graph(
|
||||
in_graph,
|
||||
out_graph=DEFAULT_OPT_GRAPH_NAME,
|
||||
inputs=DEFAULT_INPUTS,
|
||||
outputs=DEFAULT_OUTPUTS,
|
||||
transforms=DEFAULT_TRANSFORMS,
|
||||
is_manual=True,
|
||||
was_optimized=True
|
||||
):
|
||||
# ...
|
||||
|
||||
tf_opt_graph = TransformGraph(
|
||||
tf_graph,
|
||||
inputs,
|
||||
outputs,
|
||||
transforms
|
||||
)
|
||||
```
|
||||
|
||||
To run graph optimization process, execute the line:
|
||||
|
||||
```
|
||||
python -m dnn_model_runner.dnn_conversion.tf.segmentation.tf_graph_optimizer --in_graph deeplab/deeplabv3_mnv2_pascal_trainval/frozen_inference_graph.pb
|
||||
```
|
||||
|
||||
As a result ``deeplab/deeplabv3_mnv2_pascal_trainval`` directory will contain ``optimized_frozen_inference_graph.pb``.
|
||||
|
||||
After we have obtained the model graphs, let's examine the below-listed steps:
|
||||
1. read TF ``frozen_inference_graph.pb`` graph
|
||||
2. read optimized TF frozen graph with OpenCV API
|
||||
3. prepare input data
|
||||
4. provide inference
|
||||
5. get colored masks from predictions
|
||||
6. visualize results
|
||||
|
||||
```python
|
||||
# get TF model graph from the obtained frozen graph
|
||||
deeplab_graph = read_deeplab_frozen_graph(deeplab_frozen_graph_path)
|
||||
|
||||
# read DeepLab frozen graph with OpenCV API
|
||||
opencv_net = cv2.dnn.readNetFromTensorflow(opt_deeplab_frozen_graph_path)
|
||||
print("OpenCV model was successfully read. Model layers: \n", opencv_net.getLayerNames())
|
||||
|
||||
# get processed image
|
||||
original_img_shape, tf_input_blob, opencv_input_img = get_processed_imgs("test_data/sem_segm/2007_000033.jpg")
|
||||
|
||||
# obtain OpenCV DNN predictions
|
||||
opencv_prediction = get_opencv_dnn_prediction(opencv_net, opencv_input_img)
|
||||
|
||||
# obtain TF model predictions
|
||||
tf_prediction = get_tf_dnn_prediction(deeplab_graph, tf_input_blob)
|
||||
|
||||
# get PASCAL VOC classes and colors
|
||||
pascal_voc_classes, pascal_voc_colors = read_colors_info("test_data/sem_segm/pascal-classes.txt")
|
||||
|
||||
# obtain colored segmentation masks
|
||||
opencv_colored_mask = get_colored_mask(original_img_shape, opencv_prediction, pascal_voc_colors)
|
||||
tf_colored_mask = get_tf_colored_mask(original_img_shape, tf_prediction, pascal_voc_colors)
|
||||
|
||||
# obtain palette of PASCAL VOC colors
|
||||
color_legend = get_legend(pascal_voc_classes, pascal_voc_colors)
|
||||
|
||||
cv2.imshow('TensorFlow Colored Mask', tf_colored_mask)
|
||||
cv2.imshow('OpenCV DNN Colored Mask', opencv_colored_mask)
|
||||
|
||||
cv2.imshow('Color Legend', color_legend)
|
||||
```
|
||||
|
||||
To provide the model inference we will use the below picture from the [PASCAL VOC](http://host.robots.ox.ac.uk/pascal/VOC/) validation dataset:
|
||||
|
||||

|
||||
|
||||
The target segmented result is:
|
||||
|
||||

|
||||
|
||||
For the PASCAL VOC colors decoding and its mapping with the predicted masks, we also need ``pascal-classes.txt`` file, which contains the full list of the PASCAL VOC classes and corresponding colors.
|
||||
|
||||
Let's go deeper into each step by the example of pretrained TF DeepLabV3 MobileNetV2:
|
||||
|
||||
* read TF ``frozen_inference_graph.pb`` graph :
|
||||
|
||||
```python
|
||||
# init deeplab model graph
|
||||
model_graph = tf.Graph()
|
||||
|
||||
# obtain
|
||||
with tf.io.gfile.GFile(frozen_graph_path, 'rb') as graph_file:
|
||||
tf_model_graph = GraphDef()
|
||||
tf_model_graph.ParseFromString(graph_file.read())
|
||||
|
||||
with model_graph.as_default():
|
||||
tf.import_graph_def(tf_model_graph, name='')
|
||||
```
|
||||
|
||||
* read optimized TF frozen graph with OpenCV API:
|
||||
|
||||
```python
|
||||
# read DeepLab frozen graph with OpenCV API
|
||||
opencv_net = cv2.dnn.readNetFromTensorflow(opt_deeplab_frozen_graph_path)
|
||||
```
|
||||
|
||||
* prepare input data with cv2.dnn.blobFromImage function:
|
||||
|
||||
```python
|
||||
# read the image
|
||||
input_img = cv2.imread(img_path, cv2.IMREAD_COLOR)
|
||||
input_img = input_img.astype(np.float32)
|
||||
|
||||
# preprocess image for TF model input
|
||||
tf_preproc_img = cv2.resize(input_img, (513, 513))
|
||||
tf_preproc_img = cv2.cvtColor(tf_preproc_img, cv2.COLOR_BGR2RGB)
|
||||
|
||||
# define preprocess parameters for OpenCV DNN
|
||||
mean = np.array([1.0, 1.0, 1.0]) * 127.5
|
||||
scale = 1 / 127.5
|
||||
|
||||
# prepare input blob to fit the model input:
|
||||
# 1. subtract mean
|
||||
# 2. scale to set pixel values from 0 to 1
|
||||
input_blob = cv2.dnn.blobFromImage(
|
||||
image=input_img,
|
||||
scalefactor=scale,
|
||||
size=(513, 513), # img target size
|
||||
mean=mean,
|
||||
swapRB=True, # BGR -> RGB
|
||||
crop=False # center crop
|
||||
)
|
||||
```
|
||||
|
||||
Please, pay attention at the preprocessing order in the ``cv2.dnn.blobFromImage`` function. Firstly, the mean value is subtracted and only then pixel values are multiplied by the defined scale.
|
||||
Therefore, to reproduce TF image preprocessing pipeline, we multiply ``mean`` by ``127.5``.
|
||||
Another important point is image preprocessing for TF DeepLab. To pass the image into TF model we need only to construct an appropriate shape, the rest image preprocessing is described in [feature_extractor.py](https://github.com/tensorflow/models/blob/master/research/deeplab/core/feature_extractor.py) and will be invoked automatically.
|
||||
|
||||
* provide OpenCV ``cv.dnn_Net`` inference:
|
||||
|
||||
```python
|
||||
# set OpenCV DNN input
|
||||
opencv_net.setInput(preproc_img)
|
||||
|
||||
# OpenCV DNN inference
|
||||
out = opencv_net.forward()
|
||||
print("OpenCV DNN segmentation prediction: \n")
|
||||
print("* shape: ", out.shape)
|
||||
|
||||
# get IDs of predicted classes
|
||||
out_predictions = np.argmax(out[0], axis=0)
|
||||
```
|
||||
|
||||
After the above code execution we will get the following output:
|
||||
|
||||
```
|
||||
OpenCV DNN segmentation prediction:
|
||||
* shape: (1, 21, 513, 513)
|
||||
|
||||
```
|
||||
|
||||
Each prediction channel out of 21, where 21 represents the number of PASCAL VOC classes, contains probabilities, which indicate how likely the pixel corresponds to the PASCAL VOC class.
|
||||
|
||||
* provide TF model inference:
|
||||
|
||||
```python
|
||||
preproc_img = np.expand_dims(preproc_img, 0)
|
||||
|
||||
# init TF session
|
||||
tf_session = Session(graph=model_graph)
|
||||
|
||||
input_tensor_name = "ImageTensor:0",
|
||||
output_tensor_name = "SemanticPredictions:0"
|
||||
|
||||
# run inference
|
||||
out = tf_session.run(
|
||||
output_tensor_name,
|
||||
feed_dict={input_tensor_name: [preproc_img]}
|
||||
)
|
||||
|
||||
print("TF segmentation model prediction: \n")
|
||||
print("* shape: ", out.shape)
|
||||
```
|
||||
|
||||
TF inference results are the following:
|
||||
|
||||
```
|
||||
TF segmentation model prediction:
|
||||
* shape: (1, 513, 513)
|
||||
```
|
||||
|
||||
TensorFlow prediction contains the indexes of corresponding PASCAL VOC classes.
|
||||
|
||||
* transform OpenCV prediction into colored mask:
|
||||
|
||||
```python
|
||||
mask_height = segm_mask.shape[0]
|
||||
mask_width = segm_mask.shape[1]
|
||||
|
||||
img_height = original_img_shape[0]
|
||||
img_width = original_img_shape[1]
|
||||
|
||||
# convert mask values into PASCAL VOC colors
|
||||
processed_mask = np.stack([colors[color_id] for color_id in segm_mask.flatten()])
|
||||
|
||||
# reshape mask into 3-channel image
|
||||
processed_mask = processed_mask.reshape(mask_height, mask_width, 3)
|
||||
processed_mask = cv2.resize(processed_mask, (img_width, img_height), interpolation=cv2.INTER_NEAREST).astype(
|
||||
np.uint8)
|
||||
|
||||
# convert colored mask from BGR to RGB
|
||||
processed_mask = cv2.cvtColor(processed_mask, cv2.COLOR_BGR2RGB)
|
||||
```
|
||||
|
||||
In this step we map the probabilities from segmentation masks with appropriate colors of the predicted classes. Let's have a look at the results:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
* transform TF prediction into colored mask:
|
||||
|
||||
```python
|
||||
colors = np.array(colors)
|
||||
processed_mask = colors[segm_mask[0]]
|
||||
|
||||
img_height = original_img_shape[0]
|
||||
img_width = original_img_shape[1]
|
||||
|
||||
processed_mask = cv2.resize(processed_mask, (img_width, img_height), interpolation=cv2.INTER_NEAREST).astype(
|
||||
np.uint8)
|
||||
|
||||
# convert colored mask from BGR to RGB for compatibility with PASCAL VOC colors
|
||||
processed_mask = cv2.cvtColor(processed_mask, cv2.COLOR_BGR2RGB)
|
||||
```
|
||||
|
||||
The result is:
|
||||
|
||||

|
||||
|
||||
As a result, we get two equal segmentation masks.
|
||||
|
||||
### Evaluation of the Models
|
||||
|
||||
The proposed in ``dnn/samples`` ``dnn_model_runner`` module allows to run the full evaluation pipeline on the PASCAL VOC dataset and test execution for the DeepLab MobileNet model.
|
||||
|
||||
#### Evaluation Mode
|
||||
|
||||
To below line represents running of the module in the evaluation mode:
|
||||
|
||||
```
|
||||
python -m dnn_model_runner.dnn_conversion.tf.segmentation.py_to_py_segm
|
||||
```
|
||||
|
||||
The model will be read into OpenCV ``cv.dnn_Net`` object. Evaluation results of TF and OpenCV models (pixel accuracy, mean IoU, inference time) will be written into the log file. Inference time values will be also depicted in a chart to generalize the obtained model information.
|
||||
|
||||
Necessary evaluation configurations are defined in the [``test_config.py``](https://github.com/opencv/opencv/tree/master/samples/dnn/dnn_model_runner/dnn_conversion/common/test/configs/test_config.py):
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TestSegmConfig:
|
||||
frame_size: int = 500
|
||||
img_root_dir: str = "./VOC2012"
|
||||
img_dir: str = os.path.join(img_root_dir, "JPEGImages/")
|
||||
img_segm_gt_dir: str = os.path.join(img_root_dir, "SegmentationClass/")
|
||||
# reduced val: https://github.com/shelhamer/fcn.berkeleyvision.org/blob/master/data/pascal/seg11valid.txt
|
||||
segm_val_file: str = os.path.join(img_root_dir, "ImageSets/Segmentation/seg11valid.txt")
|
||||
colour_file_cls: str = os.path.join(img_root_dir, "ImageSets/Segmentation/pascal-classes.txt")
|
||||
```
|
||||
|
||||
These values can be modified in accordance with chosen model pipeline.
|
||||
|
||||
#### Test Mode
|
||||
|
||||
The below line represents running of the module in the test mode, which provides the steps for the model inference:
|
||||
|
||||
```
|
||||
python -m dnn_model_runner.dnn_conversion.tf.segmentation.py_to_py_segm --test True --default_img_preprocess <True/False> --evaluate False
|
||||
```
|
||||
|
||||
Here ``default_img_preprocess`` key defines whether you'd like to parametrize the model test process with some particular values or use the default values, for example, ``scale``, ``mean`` or ``std``.
|
||||
|
||||
Test configuration is represented in [``test_config.py``](https://github.com/opencv/opencv/tree/master/samples/dnn/dnn_model_runner/dnn_conversion/common/test/configs/test_config.py) ``TestSegmModuleConfig`` class:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TestSegmModuleConfig:
|
||||
segm_test_data_dir: str = "test_data/sem_segm"
|
||||
test_module_name: str = "segmentation"
|
||||
test_module_path: str = "segmentation.py"
|
||||
input_img: str = os.path.join(segm_test_data_dir, "2007_000033.jpg")
|
||||
model: str = ""
|
||||
|
||||
frame_height: str = str(TestSegmConfig.frame_size)
|
||||
frame_width: str = str(TestSegmConfig.frame_size)
|
||||
scale: float = 1.0
|
||||
mean: List[float] = field(default_factory=lambda: [0.0, 0.0, 0.0])
|
||||
std: List[float] = field(default_factory=list)
|
||||
crop: bool = False
|
||||
rgb: bool = True
|
||||
classes: str = os.path.join(segm_test_data_dir, "pascal-classes.txt")
|
||||
```
|
||||
|
||||
The default image preprocessing options are defined in ``default_preprocess_config.py``:
|
||||
|
||||
```python
|
||||
tf_segm_input_blob = {
|
||||
"scale": str(1 / 127.5),
|
||||
"mean": ["127.5", "127.5", "127.5"],
|
||||
"std": [],
|
||||
"crop": "False",
|
||||
"rgb": "True"
|
||||
}
|
||||
```
|
||||
|
||||
The basis of the model testing is represented in ``samples/dnn/segmentation.py``. ``segmentation.py`` can be executed autonomously with provided converted model in ``--input`` and populated parameters for ``cv2.dnn.blobFromImage``.
|
||||
|
||||
To reproduce from scratch the described in "Model Conversion Pipeline" OpenCV steps with ``dnn_model_runner`` execute the below line:
|
||||
|
||||
```
|
||||
python -m dnn_model_runner.dnn_conversion.tf.segmentation.py_to_py_segm --test True --default_img_preprocess True --evaluate False
|
||||
```
|
||||
@@ -15,7 +15,10 @@ Deep Neural Networks (dnn module) {#tutorial_table_of_content_dnn}
|
||||
In this section you will find the guides, which describe how to run classification, segmentation and detection PyTorch DNN models with OpenCV.
|
||||
- @subpage pytorch_cls_tutorial_dnn_conversion
|
||||
- @subpage pytorch_cls_c_tutorial_dnn_conversion
|
||||
- @subpage pytorch_segm_tutorial_dnn_conversion
|
||||
|
||||
#### TensorFlow models with OpenCV
|
||||
In this section you will find the guides, which describe how to run classification, segmentation and detection TensorFlow DNN models with OpenCV.
|
||||
- @subpage tf_cls_tutorial_dnn_conversion
|
||||
- @subpage tf_det_tutorial_dnn_conversion
|
||||
- @subpage tf_segm_tutorial_dnn_conversion
|
||||
|
||||
@@ -396,13 +396,14 @@ There are multiple less popular frameworks which can be used to read and write v
|
||||
|
||||
### videoio plugins
|
||||
|
||||
Some _videoio_ backends can be built as plugins thus breaking strict dependency on third-party libraries and making them optional at runtime. Following options can be used to control this mechanism:
|
||||
Since version 4.1.0 some _videoio_ backends can be built as plugins thus breaking strict dependency on third-party libraries and making them optional at runtime. Following options can be used to control this mechanism:
|
||||
|
||||
| Option | Default | Description |
|
||||
| --------| ------ | ------- |
|
||||
| `VIDEOIO_ENABLE_PLUGINS` | _ON_ | Enable or disable plugins completely. |
|
||||
| `VIDEOIO_PLUGIN_LIST` | _empty_ | Comma- or semicolon-separated list of backend names to be compiled as plugins. Supported names are _ffmpeg_, _gstreamer_, _msmf_, _mfx_ and _all_. |
|
||||
| `VIDEOIO_ENABLE_STRICT_PLUGIN_CHECK` | _ON_ | Enable strict runtime version check to only allow plugins built with the same version of OpenCV. |
|
||||
|
||||
Check @ref tutorial_general_install for standalone plugins build instructions.
|
||||
|
||||
|
||||
## Parallel processing {#tutorial_config_reference_func_core}
|
||||
@@ -421,6 +422,17 @@ Some of OpenCV algorithms can use multithreading to accelerate processing. OpenC
|
||||
@note OpenCV can download and build TBB library from GitHub, this functionality can be enabled with the `BUILD_TBB` option.
|
||||
|
||||
|
||||
### Threading plugins
|
||||
|
||||
Since version 4.5.2 OpenCV supports dynamically loaded threading backends. At this moment only separate compilation process is supported: first you have to build OpenCV with some _default_ parallel backend (e.g. pthreads), then build each plugin and copy resulting binaries to the _lib_ or _bin_ folder.
|
||||
|
||||
| Option | Default | Description |
|
||||
| ------ | ------- | ----------- |
|
||||
| PARALLEL_ENABLE_PLUGINS | ON | Enable plugin support, if this option is disabled OpenCV will not try to load anything |
|
||||
|
||||
Check @ref tutorial_general_install for standalone plugins build instructions.
|
||||
|
||||
|
||||
## GUI backends (highgui module) {#tutorial_config_reference_highgui}
|
||||
|
||||
OpenCV relies on various GUI libraries for window drawing.
|
||||
@@ -442,6 +454,18 @@ OpenCV relies on various GUI libraries for window drawing.
|
||||
OpenGL integration can be used to draw HW-accelerated windows with following backends: GTK, WIN32 and Qt. And enables basic interoperability with OpenGL, see @ref core_opengl and @ref highgui_opengl for details.
|
||||
|
||||
|
||||
### highgui plugins
|
||||
|
||||
Since OpenCV 4.5.3 GTK backend can be build as a dynamically loaded plugin. Following options can be used to control this mechanism:
|
||||
|
||||
| Option | Default | Description |
|
||||
| --------| ------ | ------- |
|
||||
| `HIGHGUI_ENABLE_PLUGINS` | _ON_ | Enable or disable plugins completely. |
|
||||
| `HIGHGUI_PLUGIN_LIST` | _empty_ | Comma- or semicolon-separated list of backend names to be compiled as plugins. Supported names are _gtk_, _gtk2_, _gtk3_, and _all_. |
|
||||
|
||||
Check @ref tutorial_general_install for standalone plugins build instructions.
|
||||
|
||||
|
||||
## Deep learning neural networks inference backends and options (dnn module) {#tutorial_config_reference_dnn}
|
||||
|
||||
OpenCV have own DNN inference module which have own build-in engine, but can also use other libraries for optimized processing. Multiple backends can be enabled in single build. Selection happens at runtime automatically or manually.
|
||||
|
||||
@@ -46,14 +46,14 @@ Open your Doxyfile using your favorite text editor and search for the key
|
||||
`TAGFILES`. Change it as follows:
|
||||
|
||||
@code
|
||||
TAGFILES = ./docs/doxygen-tags/opencv.tag=http://docs.opencv.org/4.5.2
|
||||
TAGFILES = ./docs/doxygen-tags/opencv.tag=http://docs.opencv.org/4.5.3
|
||||
@endcode
|
||||
|
||||
If you had other definitions already, you can append the line using a `\`:
|
||||
|
||||
@code
|
||||
TAGFILES = ./docs/doxygen-tags/libstdc++.tag=https://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen \
|
||||
./docs/doxygen-tags/opencv.tag=http://docs.opencv.org/4.5.2
|
||||
./docs/doxygen-tags/opencv.tag=http://docs.opencv.org/4.5.3
|
||||
@endcode
|
||||
|
||||
Doxygen can now use the information from the tag file to link to the OpenCV
|
||||
|
||||
@@ -105,7 +105,7 @@ cmake --build <build-directory> <build-options>
|
||||
make
|
||||
```
|
||||
|
||||
## Step 3: Install {#tutorial_general_install_sources_4}
|
||||
## (optional) Step 3: Install {#tutorial_general_install_sources_4}
|
||||
|
||||
During installation procedure build results and other files from build directory will be copied to the install location. Default installation location is `/usr/local` on UNIX and `C:/Program Files` on Windows. This location can be changed at the configuration step by setting `CMAKE_INSTALL_PREFIX` option. To perform installation run the following command:
|
||||
```
|
||||
@@ -117,3 +117,32 @@ This step is optional, OpenCV can be used directly from the build directory.
|
||||
|
||||
@note
|
||||
If the installation root location is a protected system directory, so the installation process must be run with superuser or administrator privileges (e.g. `sudo cmake ...`).
|
||||
|
||||
|
||||
## (optional) Step 4: Build plugins {#tutorial_general_install_plugins_4}
|
||||
|
||||
It is possible to decouple some of OpenCV dependencies and make them optional by extracting parts of the code into dynamically-loaded plugins. It helps to produce adaptive binary distributions which can work on systems with less dependencies and extend functionality just by installing missing libraries. For now modules _core_, _videoio_ and _highgui_ support this mechanism for some of their dependencies. In some cases it is possible to build plugins together with OpenCV by setting options like `VIDEOIO_PLUGIN_LIST` or `HIGHGUI_PLUGIN_LIST`, more options related to this scenario can be found in the @ref tutorial_config_reference. In other cases plugins should be built separately in their own build procedure and this section describes such standalone build process.
|
||||
|
||||
@note It is recommended to use compiler, configuration and build options which are compatible to the one used for OpenCV build, otherwise resulting library can refuse to load or cause other runtime problems. Note that some functionality can be limited or work slower when backends are loaded dynamically due to extra barrier between OpenCV and corresponding third-party library.
|
||||
|
||||
Build procedure is similar to the main OpenCV build, but you have to use special CMake projects located in corresponding subdirectories, these folders can also contain reference scripts and Docker images. It is important to use `opencv_<module>_<backend>` name prefix for plugins so that loader is able to find them. Each supported prefix can be used to load only one library, however multiple candidates can be probed for a single prefix. For example, you can have _libopencv_videoio_ffmpeg_3.so_ and _libopencv_videoio_ffmpeg_4.so_ plugins and the first one which can be loaded successfully will occupy internal slot and stop probing process. Possible prefixes and project locations are presented in the table below:
|
||||
|
||||
| module | backends | location |
|
||||
| ------ | -------- | -------- |
|
||||
| core | parallel_tbb, parallel_onetbb, parallel_openmp | _opencv/modules/core/misc/plugins_ |
|
||||
| highgui | gtk, gtk2, gtk3 | _opencv/modules/highgui/misc/plugins_ |
|
||||
| videoio | ffmpeg, gstreamer, intel_mfx, msmf | _opencv/modules/videoio/misc_ |
|
||||
|
||||
Example:
|
||||
```.sh
|
||||
# set-up environment for TBB detection, for example:
|
||||
# export TBB_DIR=<dir-with-tbb-cmake-config>
|
||||
cmake -G<generator> \
|
||||
-DOPENCV_PLUGIN_NAME=opencv_core_tbb_<suffix> \
|
||||
-DOPENCV_PLUGIN_DESTINATION=<dest-folder> \
|
||||
-DCMAKE_BUILD_TYPE=<config> \
|
||||
<opencv>/modules/core/misc/plugins/parallel_tbb
|
||||
cmake --build . --config <config>
|
||||
```
|
||||
|
||||
@note On Windows plugins must be linked with existing OpenCV build. Set `OpenCV_DIR` environment or CMake variable to the directory with _OpenCVConfig.cmake_ file, it can be OpenCV build directory or some path in the location where you performed installation.
|
||||
|
||||
@@ -108,7 +108,7 @@ CMake package files will be located in the build root:
|
||||
## Install
|
||||
|
||||
@warning
|
||||
Installation process only copies files to predefined locations and do minor patching. Library installed using this method is not integrated into the system package registry and can not be uninstalled automatically. We do not recommend system-wide installation to regular users due to possible conflicts with system packages.
|
||||
The installation process only copies files to predefined locations and does minor patching. Installing using this method does not integrate opencv into the system package registry and thus, for example, opencv can not be uninstalled automatically. We do not recommend system-wide installation to regular users due to possible conflicts with system packages.
|
||||
|
||||
By default OpenCV will be installed to the `/usr/local` directory, all files will be copied to following locations:
|
||||
* `/usr/local/bin` - executable files
|
||||
|
||||
@@ -748,7 +748,7 @@ CV_EXPORTS_W Mat findHomography(InputArray srcPoints, InputArray dstPoints, Outp
|
||||
@param Qz Optional output 3x3 rotation matrix around z-axis.
|
||||
|
||||
The function computes a RQ decomposition using the given rotations. This function is used in
|
||||
decomposeProjectionMatrix to decompose the left 3x3 submatrix of a projection matrix into a camera
|
||||
#decomposeProjectionMatrix to decompose the left 3x3 submatrix of a projection matrix into a camera
|
||||
and a rotation matrix.
|
||||
|
||||
It optionally returns three rotation matrices, one for each axis, and the three Euler angles in
|
||||
@@ -802,7 +802,7 @@ CV_EXPORTS_W void decomposeProjectionMatrix( InputArray projMatrix, OutputArray
|
||||
|
||||
The function computes partial derivatives of the elements of the matrix product \f$A*B\f$ with regard to
|
||||
the elements of each of the two input matrices. The function is used to compute the Jacobian
|
||||
matrices in stereoCalibrate but can also be used in any other similar optimization function.
|
||||
matrices in #stereoCalibrate but can also be used in any other similar optimization function.
|
||||
*/
|
||||
CV_EXPORTS_W void matMulDeriv( InputArray A, InputArray B, OutputArray dABdA, OutputArray dABdB );
|
||||
|
||||
@@ -831,7 +831,7 @@ where \f$\mathrm{rodrigues}\f$ denotes a rotation vector to a rotation matrix tr
|
||||
\f$\mathrm{rodrigues}^{-1}\f$ denotes the inverse transformation. See Rodrigues for details.
|
||||
|
||||
Also, the functions can compute the derivatives of the output vectors with regards to the input
|
||||
vectors (see matMulDeriv ). The functions are used inside stereoCalibrate but can also be used in
|
||||
vectors (see matMulDeriv ). The functions are used inside #stereoCalibrate but can also be used in
|
||||
your own code where Levenberg-Marquardt or another gradient-based solver is used to optimize a
|
||||
function that contains a matrix multiplication.
|
||||
*/
|
||||
@@ -1052,7 +1052,7 @@ a 3D point expressed in the world frame into the camera frame:
|
||||
arrays (enforced by the assertion using cv::Mat::checkVector() around line 55 of
|
||||
modules/calib3d/src/solvepnp.cpp version 2.4.9)
|
||||
- The P3P algorithm requires image points to be in an array of shape (N,1,2) due
|
||||
to its calling of cv::undistortPoints (around line 75 of modules/calib3d/src/solvepnp.cpp version 2.4.9)
|
||||
to its calling of #undistortPoints (around line 75 of modules/calib3d/src/solvepnp.cpp version 2.4.9)
|
||||
which requires 2-channel information.
|
||||
- Thus, given some data D = np.array(...) where D.shape = (N,M), in order to use a subset of
|
||||
it as, e.g., imagePoints, one must effectively copy it into a new array: imagePoints =
|
||||
@@ -1257,7 +1257,7 @@ vectors, respectively, and further optimizes them.
|
||||
- @ref SOLVEPNP_ITERATIVE Iterative method is based on a Levenberg-Marquardt optimization. In
|
||||
this case the function finds such a pose that minimizes reprojection error, that is the sum
|
||||
of squared distances between the observed projections imagePoints and the projected (using
|
||||
projectPoints ) objectPoints .
|
||||
#projectPoints ) objectPoints .
|
||||
- @ref SOLVEPNP_P3P Method is based on the paper of X.S. Gao, X.-R. Hou, J. Tang, H.-F. Chang
|
||||
"Complete Solution Classification for the Perspective-Three-Point Problem" (@cite gao2003complete).
|
||||
In this case the function requires exactly four object and image points.
|
||||
@@ -1393,7 +1393,7 @@ a 3D point expressed in the world frame into the camera frame:
|
||||
arrays (enforced by the assertion using cv::Mat::checkVector() around line 55 of
|
||||
modules/calib3d/src/solvepnp.cpp version 2.4.9)
|
||||
- The P3P algorithm requires image points to be in an array of shape (N,1,2) due
|
||||
to its calling of cv::undistortPoints (around line 75 of modules/calib3d/src/solvepnp.cpp version 2.4.9)
|
||||
to its calling of #undistortPoints (around line 75 of modules/calib3d/src/solvepnp.cpp version 2.4.9)
|
||||
which requires 2-channel information.
|
||||
- Thus, given some data D = np.array(...) where D.shape = (N,M), in order to use a subset of
|
||||
it as, e.g., imagePoints, one must effectively copy it into a new array: imagePoints =
|
||||
@@ -1426,7 +1426,7 @@ CV_EXPORTS_W int solvePnPGeneric( InputArray objectPoints, InputArray imagePoint
|
||||
|
||||
@param objectPoints Vector of vectors of the calibration pattern points in the calibration pattern
|
||||
coordinate space. In the old interface all the per-view vectors are concatenated. See
|
||||
calibrateCamera for details.
|
||||
#calibrateCamera for details.
|
||||
@param imagePoints Vector of vectors of the projections of the calibration pattern points. In the
|
||||
old interface all the per-view vectors are concatenated.
|
||||
@param imageSize Image size in pixels used to initialize the principal point.
|
||||
@@ -1520,7 +1520,7 @@ Each entry stands for one corner of the pattern and can have one of the followin
|
||||
- 3 = left-top corner of a black cell with a white marker dot
|
||||
- 4 = left-top corner of a white cell with a black marker dot (pattern origin in case of markers otherwise first corner)
|
||||
|
||||
The function is analog to findchessboardCorners but uses a localized radon
|
||||
The function is analog to #findChessboardCorners but uses a localized radon
|
||||
transformation approximated by box filters being more robust to all sort of
|
||||
noise, faster on larger images and is able to directly return the sub-pixel
|
||||
position of the internal chessboard corners. The Method is based on the paper
|
||||
@@ -1570,7 +1570,7 @@ and should be below ~3.0 pixels.
|
||||
|
||||
@param image Gray image used to find chessboard corners
|
||||
@param patternSize Size of a found chessboard pattern
|
||||
@param corners Corners found by findChessboardCorners(SB)
|
||||
@param corners Corners found by #findChessboardCornersSB
|
||||
@param rise_distance Rise distance 0.8 means 10% ... 90% of the final signal strength
|
||||
@param vertical By default edge responses for horizontal lines are calculated
|
||||
@param sharpness Optional output array with a sharpness value for calculated edge responses (see description)
|
||||
@@ -1598,9 +1598,9 @@ CV_EXPORTS_W bool find4QuadCornerSubpix( InputArray img, InputOutputArray corner
|
||||
@param image Destination image. It must be an 8-bit color image.
|
||||
@param patternSize Number of inner corners per a chessboard row and column
|
||||
(patternSize = cv::Size(points_per_row,points_per_column)).
|
||||
@param corners Array of detected corners, the output of findChessboardCorners.
|
||||
@param corners Array of detected corners, the output of #findChessboardCorners.
|
||||
@param patternWasFound Parameter indicating whether the complete board was found or not. The
|
||||
return value of findChessboardCorners should be passed here.
|
||||
return value of #findChessboardCorners should be passed here.
|
||||
|
||||
The function draws individual chessboard corners detected either as red circles if the board was not
|
||||
found, or as colored corners connected with lines if the board was found.
|
||||
@@ -1721,8 +1721,8 @@ concatenated together.
|
||||
@param imageSize Size of the image used only to initialize the camera intrinsic matrix.
|
||||
@param cameraMatrix Input/output 3x3 floating-point camera intrinsic matrix
|
||||
\f$\cameramatrix{A}\f$ . If @ref CALIB_USE_INTRINSIC_GUESS
|
||||
and/or @ref CALIB_FIX_ASPECT_RATIO are specified, some or all of fx, fy, cx, cy must be
|
||||
initialized before calling the function.
|
||||
and/or @ref CALIB_FIX_ASPECT_RATIO, @ref CALIB_FIX_PRINCIPAL_POINT or @ref CALIB_FIX_FOCAL_LENGTH
|
||||
are specified, some or all of fx, fy, cx, cy must be initialized before calling the function.
|
||||
@param distCoeffs Input/output vector of distortion coefficients
|
||||
\f$\distcoeffs\f$.
|
||||
@param rvecs Output vector of rotation vectors (@ref Rodrigues ) estimated for each pattern view
|
||||
@@ -1748,7 +1748,7 @@ the number of pattern views. \f$R_i, T_i\f$ are concatenated 1x3 vectors.
|
||||
fx, fy, cx, cy that are optimized further. Otherwise, (cx, cy) is initially set to the image
|
||||
center ( imageSize is used), and focal distances are computed in a least-squares fashion.
|
||||
Note, that if intrinsic parameters are known, there is no need to use this function just to
|
||||
estimate extrinsic parameters. Use solvePnP instead.
|
||||
estimate extrinsic parameters. Use @ref solvePnP instead.
|
||||
- @ref CALIB_FIX_PRINCIPAL_POINT The principal point is not changed during the global
|
||||
optimization. It stays at the center or at a different location specified when
|
||||
@ref CALIB_USE_INTRINSIC_GUESS is set too.
|
||||
@@ -1758,24 +1758,23 @@ ratio fx/fy stays the same as in the input cameraMatrix . When
|
||||
ignored, only their ratio is computed and used further.
|
||||
- @ref CALIB_ZERO_TANGENT_DIST Tangential distortion coefficients \f$(p_1, p_2)\f$ are set
|
||||
to zeros and stay zero.
|
||||
- @ref CALIB_FIX_FOCAL_LENGTH The focal length is not changed during the global optimization if
|
||||
@ref CALIB_USE_INTRINSIC_GUESS is set.
|
||||
- @ref CALIB_FIX_K1,..., @ref CALIB_FIX_K6 The corresponding radial distortion
|
||||
coefficient is not changed during the optimization. If @ref CALIB_USE_INTRINSIC_GUESS is
|
||||
set, the coefficient from the supplied distCoeffs matrix is used. Otherwise, it is set to 0.
|
||||
- @ref CALIB_RATIONAL_MODEL Coefficients k4, k5, and k6 are enabled. To provide the
|
||||
backward compatibility, this extra flag should be explicitly specified to make the
|
||||
calibration function use the rational model and return 8 coefficients. If the flag is not
|
||||
set, the function computes and returns only 5 distortion coefficients.
|
||||
calibration function use the rational model and return 8 coefficients or more.
|
||||
- @ref CALIB_THIN_PRISM_MODEL Coefficients s1, s2, s3 and s4 are enabled. To provide the
|
||||
backward compatibility, this extra flag should be explicitly specified to make the
|
||||
calibration function use the thin prism model and return 12 coefficients. If the flag is not
|
||||
set, the function computes and returns only 5 distortion coefficients.
|
||||
calibration function use the thin prism model and return 12 coefficients or more.
|
||||
- @ref CALIB_FIX_S1_S2_S3_S4 The thin prism distortion coefficients are not changed during
|
||||
the optimization. If @ref CALIB_USE_INTRINSIC_GUESS is set, the coefficient from the
|
||||
supplied distCoeffs matrix is used. Otherwise, it is set to 0.
|
||||
- @ref CALIB_TILTED_MODEL Coefficients tauX and tauY are enabled. To provide the
|
||||
backward compatibility, this extra flag should be explicitly specified to make the
|
||||
calibration function use the tilted sensor model and return 14 coefficients. If the flag is not
|
||||
set, the function computes and returns only 5 distortion coefficients.
|
||||
calibration function use the tilted sensor model and return 14 coefficients.
|
||||
- @ref CALIB_FIX_TAUX_TAUY The coefficients of the tilted sensor model are not changed during
|
||||
the optimization. If @ref CALIB_USE_INTRINSIC_GUESS is set, the coefficient from the
|
||||
supplied distCoeffs matrix is used. Otherwise, it is set to 0.
|
||||
@@ -1800,12 +1799,12 @@ The algorithm performs the following steps:
|
||||
zeros initially unless some of CALIB_FIX_K? are specified.
|
||||
|
||||
- Estimate the initial camera pose as if the intrinsic parameters have been already known. This is
|
||||
done using solvePnP .
|
||||
done using @ref solvePnP .
|
||||
|
||||
- Run the global Levenberg-Marquardt optimization algorithm to minimize the reprojection error,
|
||||
that is, the total sum of squared distances between the observed feature points imagePoints and
|
||||
the projected (using the current estimates for camera parameters and the poses) object points
|
||||
objectPoints. See projectPoints for details.
|
||||
objectPoints. See @ref projectPoints for details.
|
||||
|
||||
@note
|
||||
If you use a non-square (i.e. non-N-by-N) grid and @ref findChessboardCorners for calibration,
|
||||
@@ -1838,21 +1837,21 @@ CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints,
|
||||
|
||||
/** @brief Finds the camera intrinsic and extrinsic parameters from several views of a calibration pattern.
|
||||
|
||||
This function is an extension of calibrateCamera() with the method of releasing object which was
|
||||
This function is an extension of #calibrateCamera with the method of releasing object which was
|
||||
proposed in @cite strobl2011iccv. In many common cases with inaccurate, unmeasured, roughly planar
|
||||
targets (calibration plates), this method can dramatically improve the precision of the estimated
|
||||
camera parameters. Both the object-releasing method and standard method are supported by this
|
||||
function. Use the parameter **iFixedPoint** for method selection. In the internal implementation,
|
||||
calibrateCamera() is a wrapper for this function.
|
||||
#calibrateCamera is a wrapper for this function.
|
||||
|
||||
@param objectPoints Vector of vectors of calibration pattern points in the calibration pattern
|
||||
coordinate space. See calibrateCamera() for details. If the method of releasing object to be used,
|
||||
coordinate space. See #calibrateCamera for details. If the method of releasing object to be used,
|
||||
the identical calibration board must be used in each view and it must be fully visible, and all
|
||||
objectPoints[i] must be the same and all points should be roughly close to a plane. **The calibration
|
||||
target has to be rigid, or at least static if the camera (rather than the calibration target) is
|
||||
shifted for grabbing images.**
|
||||
@param imagePoints Vector of vectors of the projections of calibration pattern points. See
|
||||
calibrateCamera() for details.
|
||||
#calibrateCamera for details.
|
||||
@param imageSize Size of the image used only to initialize the intrinsic camera matrix.
|
||||
@param iFixedPoint The index of the 3D object point in objectPoints[0] to be fixed. It also acts as
|
||||
a switch for calibration method selection. If object-releasing method to be used, pass in the
|
||||
@@ -1862,9 +1861,9 @@ board grid is recommended to be fixed when object-releasing method being utilize
|
||||
\cite strobl2011iccv, two other points are also fixed. In this implementation, objectPoints[0].front
|
||||
and objectPoints[0].back.z are used. With object-releasing method, accurate rvecs, tvecs and
|
||||
newObjPoints are only possible if coordinates of these three fixed points are accurate enough.
|
||||
@param cameraMatrix Output 3x3 floating-point camera matrix. See calibrateCamera() for details.
|
||||
@param distCoeffs Output vector of distortion coefficients. See calibrateCamera() for details.
|
||||
@param rvecs Output vector of rotation vectors estimated for each pattern view. See calibrateCamera()
|
||||
@param cameraMatrix Output 3x3 floating-point camera matrix. See #calibrateCamera for details.
|
||||
@param distCoeffs Output vector of distortion coefficients. See #calibrateCamera for details.
|
||||
@param rvecs Output vector of rotation vectors estimated for each pattern view. See #calibrateCamera
|
||||
for details.
|
||||
@param tvecs Output vector of translation vectors estimated for each pattern view.
|
||||
@param newObjPoints The updated output vector of calibration pattern points. The coordinates might
|
||||
@@ -1872,15 +1871,15 @@ be scaled based on three fixed points. The returned coordinates are accurate onl
|
||||
mentioned three fixed points are accurate. If not needed, noArray() can be passed in. This parameter
|
||||
is ignored with standard calibration method.
|
||||
@param stdDeviationsIntrinsics Output vector of standard deviations estimated for intrinsic parameters.
|
||||
See calibrateCamera() for details.
|
||||
See #calibrateCamera for details.
|
||||
@param stdDeviationsExtrinsics Output vector of standard deviations estimated for extrinsic parameters.
|
||||
See calibrateCamera() for details.
|
||||
See #calibrateCamera for details.
|
||||
@param stdDeviationsObjPoints Output vector of standard deviations estimated for refined coordinates
|
||||
of calibration pattern points. It has the same size and order as objectPoints[0] vector. This
|
||||
parameter is ignored with standard calibration method.
|
||||
@param perViewErrors Output vector of the RMS re-projection error estimated for each pattern view.
|
||||
@param flags Different flags that may be zero or a combination of some predefined values. See
|
||||
calibrateCamera() for details. If the method of releasing object is used, the calibration time may
|
||||
#calibrateCamera for details. If the method of releasing object is used, the calibration time may
|
||||
be much longer. CALIB_USE_QR or CALIB_USE_LU could be used for faster calibration with potentially
|
||||
less precise and less stable in some rare cases.
|
||||
@param criteria Termination criteria for the iterative optimization algorithm.
|
||||
@@ -1889,7 +1888,7 @@ less precise and less stable in some rare cases.
|
||||
|
||||
The function estimates the intrinsic camera parameters and extrinsic parameters for each of the
|
||||
views. The algorithm is based on @cite Zhang2000, @cite BouguetMCT and @cite strobl2011iccv. See
|
||||
calibrateCamera() for other detailed explanations.
|
||||
#calibrateCamera for other detailed explanations.
|
||||
@sa
|
||||
calibrateCamera, findChessboardCorners, solvePnP, initCameraMatrix2D, stereoCalibrate, undistort
|
||||
*/
|
||||
@@ -1916,8 +1915,8 @@ CV_EXPORTS_W double calibrateCameraRO( InputArrayOfArrays objectPoints,
|
||||
|
||||
/** @brief Computes useful camera characteristics from the camera intrinsic matrix.
|
||||
|
||||
@param cameraMatrix Input camera intrinsic matrix that can be estimated by calibrateCamera or
|
||||
stereoCalibrate .
|
||||
@param cameraMatrix Input camera intrinsic matrix that can be estimated by #calibrateCamera or
|
||||
#stereoCalibrate .
|
||||
@param imageSize Input image size in pixels.
|
||||
@param apertureWidth Physical width in mm of the sensor.
|
||||
@param apertureHeight Physical height in mm of the sensor.
|
||||
@@ -2052,13 +2051,13 @@ Besides the stereo-related information, the function can also perform a full cal
|
||||
the two cameras. However, due to the high dimensionality of the parameter space and noise in the
|
||||
input data, the function can diverge from the correct solution. If the intrinsic parameters can be
|
||||
estimated with high accuracy for each of the cameras individually (for example, using
|
||||
calibrateCamera ), you are recommended to do so and then pass @ref CALIB_FIX_INTRINSIC flag to the
|
||||
#calibrateCamera ), you are recommended to do so and then pass @ref CALIB_FIX_INTRINSIC flag to the
|
||||
function along with the computed intrinsic parameters. Otherwise, if all the parameters are
|
||||
estimated at once, it makes sense to restrict some parameters, for example, pass
|
||||
@ref CALIB_SAME_FOCAL_LENGTH and @ref CALIB_ZERO_TANGENT_DIST flags, which is usually a
|
||||
reasonable assumption.
|
||||
|
||||
Similarly to calibrateCamera, the function minimizes the total re-projection error for all the
|
||||
Similarly to #calibrateCamera, the function minimizes the total re-projection error for all the
|
||||
points in all the available views from both cameras. The function returns the final value of the
|
||||
re-projection error.
|
||||
*/
|
||||
@@ -2118,7 +2117,7 @@ pixels from the original images from the cameras are retained in the rectified i
|
||||
image pixels are lost). Any intermediate value yields an intermediate result between
|
||||
those two extreme cases.
|
||||
@param newImageSize New image resolution after rectification. The same size should be passed to
|
||||
initUndistortRectifyMap (see the stereo_calib.cpp sample in OpenCV samples directory). When (0,0)
|
||||
#initUndistortRectifyMap (see the stereo_calib.cpp sample in OpenCV samples directory). When (0,0)
|
||||
is passed (default), it is set to the original imageSize . Setting it to a larger value can help you
|
||||
preserve details in the original image, especially when there is a big radial distortion.
|
||||
@param validPixROI1 Optional output rectangles inside the rectified images where all the pixels
|
||||
@@ -2130,7 +2129,7 @@ are valid. If alpha=0 , the ROIs cover the whole images. Otherwise, they are lik
|
||||
|
||||
The function computes the rotation matrices for each camera that (virtually) make both camera image
|
||||
planes the same plane. Consequently, this makes all the epipolar lines parallel and thus simplifies
|
||||
the dense stereo correspondence problem. The function takes the matrices computed by stereoCalibrate
|
||||
the dense stereo correspondence problem. The function takes the matrices computed by #stereoCalibrate
|
||||
as input. As output, it provides two rotation matrices and also two projection matrices in the new
|
||||
coordinates. The function distinguishes the following two cases:
|
||||
|
||||
@@ -2174,7 +2173,7 @@ coordinates. The function distinguishes the following two cases:
|
||||
@ref CALIB_ZERO_DISPARITY is set.
|
||||
|
||||
As you can see, the first three columns of P1 and P2 will effectively be the new "rectified" camera
|
||||
matrices. The matrices, together with R1 and R2 , can then be passed to initUndistortRectifyMap to
|
||||
matrices. The matrices, together with R1 and R2 , can then be passed to #initUndistortRectifyMap to
|
||||
initialize the rectification map for each camera.
|
||||
|
||||
See below the screenshot from the stereo_calib.cpp sample. Some red horizontal lines pass through
|
||||
@@ -2197,9 +2196,9 @@ CV_EXPORTS_W void stereoRectify( InputArray cameraMatrix1, InputArray distCoeffs
|
||||
|
||||
@param points1 Array of feature points in the first image.
|
||||
@param points2 The corresponding points in the second image. The same formats as in
|
||||
findFundamentalMat are supported.
|
||||
#findFundamentalMat are supported.
|
||||
@param F Input fundamental matrix. It can be computed from the same set of point pairs using
|
||||
findFundamentalMat .
|
||||
#findFundamentalMat .
|
||||
@param imgSize Size of the image.
|
||||
@param H1 Output rectification homography matrix for the first image.
|
||||
@param H2 Output rectification homography matrix for the second image.
|
||||
@@ -2210,7 +2209,7 @@ rejected prior to computing the homographies. Otherwise, all the points are cons
|
||||
|
||||
The function computes the rectification transformations without knowing intrinsic parameters of the
|
||||
cameras and their relative position in the space, which explains the suffix "uncalibrated". Another
|
||||
related difference from stereoRectify is that the function outputs not the rectification
|
||||
related difference from #stereoRectify is that the function outputs not the rectification
|
||||
transformations in the object (3D) space, but the planar perspective transformations encoded by the
|
||||
homography matrices H1 and H2 . The function implements the algorithm @cite Hartley99 .
|
||||
|
||||
@@ -2219,8 +2218,8 @@ homography matrices H1 and H2 . The function implements the algorithm @cite Hart
|
||||
depends on the epipolar geometry. Therefore, if the camera lenses have a significant distortion,
|
||||
it would be better to correct it before computing the fundamental matrix and calling this
|
||||
function. For example, distortion coefficients can be estimated for each head of stereo camera
|
||||
separately by using calibrateCamera . Then, the images can be corrected using undistort , or
|
||||
just the point coordinates can be corrected with undistortPoints .
|
||||
separately by using #calibrateCamera . Then, the images can be corrected using #undistort , or
|
||||
just the point coordinates can be corrected with #undistortPoints .
|
||||
*/
|
||||
CV_EXPORTS_W bool stereoRectifyUncalibrated( InputArray points1, InputArray points2,
|
||||
InputArray F, Size imgSize,
|
||||
@@ -2248,10 +2247,10 @@ assumed.
|
||||
@param imageSize Original image size.
|
||||
@param alpha Free scaling parameter between 0 (when all the pixels in the undistorted image are
|
||||
valid) and 1 (when all the source image pixels are retained in the undistorted image). See
|
||||
stereoRectify for details.
|
||||
#stereoRectify for details.
|
||||
@param newImgSize Image size after rectification. By default, it is set to imageSize .
|
||||
@param validPixROI Optional output rectangle that outlines all-good-pixels region in the
|
||||
undistorted image. See roi1, roi2 description in stereoRectify .
|
||||
undistorted image. See roi1, roi2 description in #stereoRectify .
|
||||
@param centerPrincipalPoint Optional flag that indicates whether in the new camera intrinsic matrix the
|
||||
principal point should be at the image center or not. By default, the principal point is chosen to
|
||||
best fit a subset of the source image (determined by alpha) to the corrected image.
|
||||
@@ -2263,7 +2262,7 @@ image pixels if there is valuable information in the corners alpha=1 , or get so
|
||||
When alpha\>0 , the undistorted result is likely to have some black pixels corresponding to
|
||||
"virtual" pixels outside of the captured distorted image. The original camera intrinsic matrix, distortion
|
||||
coefficients, the computed new camera intrinsic matrix, and newImageSize should be passed to
|
||||
initUndistortRectifyMap to produce the maps for remap .
|
||||
#initUndistortRectifyMap to produce the maps for #remap .
|
||||
*/
|
||||
CV_EXPORTS_W Mat getOptimalNewCameraMatrix( InputArray cameraMatrix, InputArray distCoeffs,
|
||||
Size imageSize, double alpha, Size newImgSize = Size(),
|
||||
@@ -2592,7 +2591,7 @@ CV_EXPORTS_W void convertPointsFromHomogeneous( InputArray src, OutputArray dst
|
||||
@param dst Output vector of 2D, 3D, or 4D points.
|
||||
|
||||
The function converts 2D or 3D points from/to homogeneous coordinates by calling either
|
||||
convertPointsToHomogeneous or convertPointsFromHomogeneous.
|
||||
#convertPointsToHomogeneous or #convertPointsFromHomogeneous.
|
||||
|
||||
@note The function is obsolete. Use one of the previous two functions instead.
|
||||
*/
|
||||
@@ -2631,7 +2630,7 @@ matrices sequentially).
|
||||
|
||||
The calculated fundamental matrix may be passed further to computeCorrespondEpilines that finds the
|
||||
epipolar lines corresponding to the specified points. It can also be passed to
|
||||
stereoRectifyUncalibrated to compute the rectification transformation. :
|
||||
#stereoRectifyUncalibrated to compute the rectification transformation. :
|
||||
@code
|
||||
// Example. Estimation of fundamental matrix using the RANSAC algorithm
|
||||
int point_count = 100;
|
||||
@@ -2676,7 +2675,7 @@ be floating-point (single or double precision).
|
||||
@param cameraMatrix Camera intrinsic matrix \f$\cameramatrix{A}\f$ .
|
||||
Note that this function assumes that points1 and points2 are feature points from cameras with the
|
||||
same camera intrinsic matrix. If this assumption does not hold for your use case, use
|
||||
`undistortPoints()` with `P = cv::NoArray()` for both cameras to transform image points
|
||||
#undistortPoints with `P = cv::NoArray()` for both cameras to transform image points
|
||||
to normalized image coordinates, which are valid for the identity camera intrinsic matrix. When
|
||||
passing these coordinates, pass the identity matrix for this parameter.
|
||||
@param method Method for computing an essential matrix.
|
||||
@@ -2690,6 +2689,7 @@ final fundamental matrix. It can be set to something like 1-3, depending on the
|
||||
point localization, image resolution, and the image noise.
|
||||
@param mask Output array of N elements, every element of which is set to 0 for outliers and to 1
|
||||
for the other points. The array is computed only in the RANSAC and LMedS methods.
|
||||
@param maxIters The maximum number of robust method iterations.
|
||||
|
||||
This function estimates essential matrix based on the five-point algorithm solver in @cite Nister03 .
|
||||
@cite SteweniusCFS is also a related. The epipolar geometry is described by the following equation:
|
||||
@@ -2698,12 +2698,24 @@ This function estimates essential matrix based on the five-point algorithm solve
|
||||
|
||||
where \f$E\f$ is an essential matrix, \f$p_1\f$ and \f$p_2\f$ are corresponding points in the first and the
|
||||
second images, respectively. The result of this function may be passed further to
|
||||
decomposeEssentialMat or recoverPose to recover the relative pose between cameras.
|
||||
#decomposeEssentialMat or #recoverPose to recover the relative pose between cameras.
|
||||
*/
|
||||
CV_EXPORTS_W Mat findEssentialMat( InputArray points1, InputArray points2,
|
||||
InputArray cameraMatrix, int method = RANSAC,
|
||||
double prob = 0.999, double threshold = 1.0,
|
||||
OutputArray mask = noArray() );
|
||||
CV_EXPORTS_W
|
||||
Mat findEssentialMat(
|
||||
InputArray points1, InputArray points2,
|
||||
InputArray cameraMatrix, int method = RANSAC,
|
||||
double prob = 0.999, double threshold = 1.0,
|
||||
int maxIters = 1000, OutputArray mask = noArray()
|
||||
);
|
||||
|
||||
/** @overload */
|
||||
CV_EXPORTS
|
||||
Mat findEssentialMat(
|
||||
InputArray points1, InputArray points2,
|
||||
InputArray cameraMatrix, int method,
|
||||
double prob, double threshold,
|
||||
OutputArray mask
|
||||
); // TODO remove from OpenCV 5.0
|
||||
|
||||
/** @overload
|
||||
@param points1 Array of N (N \>= 5) 2D points from the first image. The point coordinates should
|
||||
@@ -2723,6 +2735,7 @@ point localization, image resolution, and the image noise.
|
||||
confidence (probability) that the estimated matrix is correct.
|
||||
@param mask Output array of N elements, every element of which is set to 0 for outliers and to 1
|
||||
for the other points. The array is computed only in the RANSAC and LMedS methods.
|
||||
@param maxIters The maximum number of robust method iterations.
|
||||
|
||||
This function differs from the one above that it computes camera intrinsic matrix from focal length and
|
||||
principal point:
|
||||
@@ -2734,10 +2747,23 @@ f & 0 & x_{pp} \\
|
||||
0 & 0 & 1
|
||||
\end{bmatrix}\f]
|
||||
*/
|
||||
CV_EXPORTS_W Mat findEssentialMat( InputArray points1, InputArray points2,
|
||||
double focal = 1.0, Point2d pp = Point2d(0, 0),
|
||||
int method = RANSAC, double prob = 0.999,
|
||||
double threshold = 1.0, OutputArray mask = noArray() );
|
||||
CV_EXPORTS_W
|
||||
Mat findEssentialMat(
|
||||
InputArray points1, InputArray points2,
|
||||
double focal = 1.0, Point2d pp = Point2d(0, 0),
|
||||
int method = RANSAC, double prob = 0.999,
|
||||
double threshold = 1.0, int maxIters = 1000,
|
||||
OutputArray mask = noArray()
|
||||
);
|
||||
|
||||
/** @overload */
|
||||
CV_EXPORTS
|
||||
Mat findEssentialMat(
|
||||
InputArray points1, InputArray points2,
|
||||
double focal, Point2d pp,
|
||||
int method, double prob,
|
||||
double threshold, OutputArray mask
|
||||
); // TODO remove from OpenCV 5.0
|
||||
|
||||
/** @brief Calculates an essential matrix from the corresponding points in two images from potentially two different cameras.
|
||||
|
||||
@@ -2747,13 +2773,13 @@ be floating-point (single or double precision).
|
||||
@param cameraMatrix1 Camera matrix \f$K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ .
|
||||
Note that this function assumes that points1 and points2 are feature points from cameras with the
|
||||
same camera matrix. If this assumption does not hold for your use case, use
|
||||
`undistortPoints()` with `P = cv::NoArray()` for both cameras to transform image points
|
||||
#undistortPoints with `P = cv::NoArray()` for both cameras to transform image points
|
||||
to normalized image coordinates, which are valid for the identity camera matrix. When
|
||||
passing these coordinates, pass the identity matrix for this parameter.
|
||||
@param cameraMatrix2 Camera matrix \f$K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ .
|
||||
Note that this function assumes that points1 and points2 are feature points from cameras with the
|
||||
same camera matrix. If this assumption does not hold for your use case, use
|
||||
`undistortPoints()` with `P = cv::NoArray()` for both cameras to transform image points
|
||||
#undistortPoints with `P = cv::NoArray()` for both cameras to transform image points
|
||||
to normalized image coordinates, which are valid for the identity camera matrix. When
|
||||
passing these coordinates, pass the identity matrix for this parameter.
|
||||
@param distCoeffs1 Input vector of distortion coefficients
|
||||
@@ -2781,7 +2807,7 @@ This function estimates essential matrix based on the five-point algorithm solve
|
||||
|
||||
where \f$E\f$ is an essential matrix, \f$p_1\f$ and \f$p_2\f$ are corresponding points in the first and the
|
||||
second images, respectively. The result of this function may be passed further to
|
||||
decomposeEssentialMat or recoverPose to recover the relative pose between cameras.
|
||||
#decomposeEssentialMat or #recoverPose to recover the relative pose between cameras.
|
||||
*/
|
||||
CV_EXPORTS_W Mat findEssentialMat( InputArray points1, InputArray points2,
|
||||
InputArray cameraMatrix1, InputArray distCoeffs1,
|
||||
@@ -2843,7 +2869,7 @@ possible pose hypotheses by doing cheirality check. The cheirality check means t
|
||||
triangulated 3D points should have positive depth. Some details can be found in @cite Nister03.
|
||||
|
||||
This function can be used to process the output E and mask from @ref findEssentialMat. In this
|
||||
scenario, points1 and points2 are the same input for findEssentialMat.:
|
||||
scenario, points1 and points2 are the same input for #findEssentialMat :
|
||||
@code
|
||||
// Example. Estimation of fundamental matrix using the RANSAC algorithm
|
||||
int point_count = 100;
|
||||
@@ -2938,14 +2964,14 @@ CV_EXPORTS_W int recoverPose( InputArray E, InputArray points1, InputArray point
|
||||
@param points Input points. \f$N \times 1\f$ or \f$1 \times N\f$ matrix of type CV_32FC2 or
|
||||
vector\<Point2f\> .
|
||||
@param whichImage Index of the image (1 or 2) that contains the points .
|
||||
@param F Fundamental matrix that can be estimated using findFundamentalMat or stereoRectify .
|
||||
@param F Fundamental matrix that can be estimated using #findFundamentalMat or #stereoRectify .
|
||||
@param lines Output vector of the epipolar lines corresponding to the points in the other image.
|
||||
Each line \f$ax + by + c=0\f$ is encoded by 3 numbers \f$(a, b, c)\f$ .
|
||||
|
||||
For every point in one of the two images of a stereo pair, the function finds the equation of the
|
||||
corresponding epipolar line in the other image.
|
||||
|
||||
From the fundamental matrix definition (see findFundamentalMat ), line \f$l^{(2)}_i\f$ in the second
|
||||
From the fundamental matrix definition (see #findFundamentalMat ), line \f$l^{(2)}_i\f$ in the second
|
||||
image for the point \f$p^{(1)}_i\f$ in the first image (when whichImage=1 ) is computed as:
|
||||
|
||||
\f[l^{(2)}_i = F p^{(1)}_i\f]
|
||||
@@ -3021,7 +3047,7 @@ CV_EXPORTS_W void filterSpeckles( InputOutputArray img, double newVal,
|
||||
int maxSpeckleSize, double maxDiff,
|
||||
InputOutputArray buf = noArray() );
|
||||
|
||||
//! computes valid disparity ROI from the valid ROIs of the rectified images (that are returned by cv::stereoRectify())
|
||||
//! computes valid disparity ROI from the valid ROIs of the rectified images (that are returned by #stereoRectify)
|
||||
CV_EXPORTS_W Rect getValidDisparityROI( Rect roi1, Rect roi2,
|
||||
int minDisparity, int numberOfDisparities,
|
||||
int blockSize );
|
||||
@@ -3086,7 +3112,7 @@ sd( \texttt{pt1} , \texttt{pt2} )=
|
||||
((\texttt{F}^t \cdot \texttt{pt2})(0))^2 +
|
||||
((\texttt{F}^t \cdot \texttt{pt2})(1))^2}
|
||||
\f]
|
||||
The fundamental matrix may be calculated using the cv::findFundamentalMat function. See @cite HartleyZ00 11.4.3 for details.
|
||||
The fundamental matrix may be calculated using the #findFundamentalMat function. See @cite HartleyZ00 11.4.3 for details.
|
||||
@param pt1 first homogeneous 2d point
|
||||
@param pt2 second homogeneous 2d point
|
||||
@param F fundamental matrix
|
||||
@@ -3146,6 +3172,33 @@ CV_EXPORTS_W int estimateAffine3D(InputArray src, InputArray dst,
|
||||
OutputArray out, OutputArray inliers,
|
||||
double ransacThreshold = 3, double confidence = 0.99);
|
||||
|
||||
/** @brief Computes an optimal affine transformation between two 3D point sets.
|
||||
|
||||
It computes \f$R,s,t\f$ minimizing \f$\sum{i} dst_i - c \cdot R \cdot src_i \f$
|
||||
where \f$R\f$ is a 3x3 rotation matrix, \f$t\f$ is a 3x1 translation vector and \f$s\f$ is a
|
||||
scalar size value. This is an implementation of the algorithm by Umeyama \cite umeyama1991least .
|
||||
The estimated affine transform has a homogeneous scale which is a subclass of affine
|
||||
transformations with 7 degrees of freedom. The paired point sets need to comprise at least 3
|
||||
points each.
|
||||
|
||||
@param src First input 3D point set.
|
||||
@param dst Second input 3D point set.
|
||||
@param scale If null is passed, the scale parameter c will be assumed to be 1.0.
|
||||
Else the pointed-to variable will be set to the optimal scale.
|
||||
@param force_rotation If true, the returned rotation will never be a reflection.
|
||||
This might be unwanted, e.g. when optimizing a transform between a right- and a
|
||||
left-handed coordinate system.
|
||||
@return 3D affine transformation matrix \f$3 \times 4\f$ of the form
|
||||
\f[T =
|
||||
\begin{bmatrix}
|
||||
R & t\\
|
||||
\end{bmatrix}
|
||||
\f]
|
||||
|
||||
*/
|
||||
CV_EXPORTS_W cv::Mat estimateAffine3D(InputArray src, InputArray dst,
|
||||
CV_OUT double* scale = nullptr, bool force_rotation = true);
|
||||
|
||||
/** @brief Computes an optimal translation between two 3D point sets.
|
||||
*
|
||||
* It computes
|
||||
@@ -3353,10 +3406,10 @@ CV_EXPORTS_W int decomposeHomographyMat(InputArray H,
|
||||
@param beforePoints Vector of (rectified) visible reference points before the homography is applied
|
||||
@param afterPoints Vector of (rectified) visible reference points after the homography is applied
|
||||
@param possibleSolutions Vector of int indices representing the viable solution set after filtering
|
||||
@param pointsMask optional Mat/Vector of 8u type representing the mask for the inliers as given by the findHomography function
|
||||
@param pointsMask optional Mat/Vector of 8u type representing the mask for the inliers as given by the #findHomography function
|
||||
|
||||
This function is intended to filter the output of the decomposeHomographyMat based on additional
|
||||
information as described in @cite Malis . The summary of the method: the decomposeHomographyMat function
|
||||
This function is intended to filter the output of the #decomposeHomographyMat based on additional
|
||||
information as described in @cite Malis . The summary of the method: the #decomposeHomographyMat function
|
||||
returns 2 unique solutions and their "opposites" for a total of 4 solutions. If we have access to the
|
||||
sets of points visible in the camera frame before and after the homography transformation is applied,
|
||||
we can determine which are the true potential solutions and which are the opposites by verifying which
|
||||
@@ -3594,7 +3647,7 @@ CV_EXPORTS_W void undistort( InputArray src, OutputArray dst,
|
||||
/** @brief Computes the undistortion and rectification transformation map.
|
||||
|
||||
The function computes the joint undistortion and rectification transformation and represents the
|
||||
result in the form of maps for remap. The undistorted image looks like original, as if it is
|
||||
result in the form of maps for #remap. The undistorted image looks like original, as if it is
|
||||
captured with a camera using the camera matrix =newCameraMatrix and zero distortion. In case of a
|
||||
monocular camera, newCameraMatrix is usually equal to cameraMatrix, or it can be computed by
|
||||
#getOptimalNewCameraMatrix for a better control over scaling. In case of a stereo camera,
|
||||
@@ -3604,7 +3657,7 @@ Also, this new camera is oriented differently in the coordinate space, according
|
||||
example, helps to align two heads of a stereo camera so that the epipolar lines on both images
|
||||
become horizontal and have the same y- coordinate (in case of a horizontally aligned stereo camera).
|
||||
|
||||
The function actually builds the maps for the inverse mapping algorithm that is used by remap. That
|
||||
The function actually builds the maps for the inverse mapping algorithm that is used by #remap. That
|
||||
is, for each pixel \f$(u, v)\f$ in the destination (corrected and rectified) image, the function
|
||||
computes the corresponding coordinates in the source image (that is, in the original image from
|
||||
camera). The following process is applied:
|
||||
@@ -3632,7 +3685,7 @@ where \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x
|
||||
are the distortion coefficients.
|
||||
|
||||
In case of a stereo camera, this function is called twice: once for each camera head, after
|
||||
stereoRectify, which in its turn is called after #stereoCalibrate. But if the stereo camera
|
||||
#stereoRectify, which in its turn is called after #stereoCalibrate. But if the stereo camera
|
||||
was not calibrated, it is still possible to compute the rectification transformations directly from
|
||||
the fundamental matrix using #stereoRectifyUncalibrated. For each camera, the function computes
|
||||
homography H as the rectification transformation in a pixel domain, not a rotation matrix R in 3D
|
||||
@@ -3658,6 +3711,77 @@ void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs,
|
||||
InputArray R, InputArray newCameraMatrix,
|
||||
Size size, int m1type, OutputArray map1, OutputArray map2);
|
||||
|
||||
/** @brief Computes the projection and inverse-rectification transformation map. In essense, this is the inverse of
|
||||
#initUndistortRectifyMap to accomodate stereo-rectification of projectors ('inverse-cameras') in projector-camera pairs.
|
||||
|
||||
The function computes the joint projection and inverse rectification transformation and represents the
|
||||
result in the form of maps for #remap. The projected image looks like a distorted version of the original which,
|
||||
once projected by a projector, should visually match the original. In case of a monocular camera, newCameraMatrix
|
||||
is usually equal to cameraMatrix, or it can be computed by
|
||||
#getOptimalNewCameraMatrix for a better control over scaling. In case of a projector-camera pair,
|
||||
newCameraMatrix is normally set to P1 or P2 computed by #stereoRectify .
|
||||
|
||||
The projector is oriented differently in the coordinate space, according to R. In case of projector-camera pairs,
|
||||
this helps align the projector (in the same manner as #initUndistortRectifyMap for the camera) to create a stereo-rectified pair. This
|
||||
allows epipolar lines on both images to become horizontal and have the same y-coordinate (in case of a horizontally aligned projector-camera pair).
|
||||
|
||||
The function builds the maps for the inverse mapping algorithm that is used by #remap. That
|
||||
is, for each pixel \f$(u, v)\f$ in the destination (projected and inverse-rectified) image, the function
|
||||
computes the corresponding coordinates in the source image (that is, in the original digital image). The following process is applied:
|
||||
|
||||
\f[
|
||||
\begin{array}{l}
|
||||
\text{newCameraMatrix}\\
|
||||
x \leftarrow (u - {c'}_x)/{f'}_x \\
|
||||
y \leftarrow (v - {c'}_y)/{f'}_y \\
|
||||
|
||||
\\\text{Undistortion}
|
||||
\\\scriptsize{\textit{though equation shown is for radial undistortion, function implements cv::undistortPoints()}}\\
|
||||
r^2 \leftarrow x^2 + y^2 \\
|
||||
\theta \leftarrow \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6}\\
|
||||
x' \leftarrow \frac{x}{\theta} \\
|
||||
y' \leftarrow \frac{y}{\theta} \\
|
||||
|
||||
\\\text{Rectification}\\
|
||||
{[X\,Y\,W]} ^T \leftarrow R*[x' \, y' \, 1]^T \\
|
||||
x'' \leftarrow X/W \\
|
||||
y'' \leftarrow Y/W \\
|
||||
|
||||
\\\text{cameraMatrix}\\
|
||||
map_x(u,v) \leftarrow x'' f_x + c_x \\
|
||||
map_y(u,v) \leftarrow y'' f_y + c_y
|
||||
\end{array}
|
||||
\f]
|
||||
where \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$
|
||||
are the distortion coefficients vector distCoeffs.
|
||||
|
||||
In case of a stereo-rectified projector-camera pair, this function is called for the projector while #initUndistortRectifyMap is called for the camera head.
|
||||
This is done after #stereoRectify, which in turn is called after #stereoCalibrate. If the projector-camera pair
|
||||
is not calibrated, it is still possible to compute the rectification transformations directly from
|
||||
the fundamental matrix using #stereoRectifyUncalibrated. For the projector and camera, the function computes
|
||||
homography H as the rectification transformation in a pixel domain, not a rotation matrix R in 3D
|
||||
space. R can be computed from H as
|
||||
\f[\texttt{R} = \texttt{cameraMatrix} ^{-1} \cdot \texttt{H} \cdot \texttt{cameraMatrix}\f]
|
||||
where cameraMatrix can be chosen arbitrarily.
|
||||
|
||||
@param cameraMatrix Input camera matrix \f$A=\vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ .
|
||||
@param distCoeffs Input vector of distortion coefficients
|
||||
\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$
|
||||
of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed.
|
||||
@param R Optional rectification transformation in the object space (3x3 matrix). R1 or R2,
|
||||
computed by #stereoRectify can be passed here. If the matrix is empty, the identity transformation
|
||||
is assumed.
|
||||
@param newCameraMatrix New camera matrix \f$A'=\vecthreethree{f_x'}{0}{c_x'}{0}{f_y'}{c_y'}{0}{0}{1}\f$.
|
||||
@param size Distorted image size.
|
||||
@param m1type Type of the first output map. Can be CV_32FC1, CV_32FC2 or CV_16SC2, see #convertMaps
|
||||
@param map1 The first output map for #remap.
|
||||
@param map2 The second output map for #remap.
|
||||
*/
|
||||
CV_EXPORTS_W
|
||||
void initInverseRectificationMap( InputArray cameraMatrix, InputArray distCoeffs,
|
||||
InputArray R, InputArray newCameraMatrix,
|
||||
const Size& size, int m1type, OutputArray map1, OutputArray map2 );
|
||||
|
||||
//! initializes maps for #remap for wide-angle
|
||||
CV_EXPORTS
|
||||
float initWideAngleProjMap(InputArray cameraMatrix, InputArray distCoeffs,
|
||||
@@ -3704,7 +3828,7 @@ Mat getDefaultNewCameraMatrix(InputArray cameraMatrix, Size imgsize = Size(),
|
||||
|
||||
The function is similar to #undistort and #initUndistortRectifyMap but it operates on a
|
||||
sparse set of points instead of a raster image. Also the function performs a reverse transformation
|
||||
to projectPoints. In case of a 3D object, it does not reconstruct its 3D coordinates, but for a
|
||||
to #projectPoints. In case of a 3D object, it does not reconstruct its 3D coordinates, but for a
|
||||
planar object, it does, up to a translation vector, if the proper R is specified.
|
||||
|
||||
For each observed point coordinate \f$(u, v)\f$ the function computes:
|
||||
@@ -3773,7 +3897,8 @@ namespace fisheye
|
||||
CALIB_FIX_K4 = 1 << 7,
|
||||
CALIB_FIX_INTRINSIC = 1 << 8,
|
||||
CALIB_FIX_PRINCIPAL_POINT = 1 << 9,
|
||||
CALIB_ZERO_DISPARITY = 1 << 10
|
||||
CALIB_ZERO_DISPARITY = 1 << 10,
|
||||
CALIB_FIX_FOCAL_LENGTH = 1 << 11
|
||||
};
|
||||
|
||||
/** @brief Projects points using fisheye model
|
||||
@@ -3813,7 +3938,7 @@ namespace fisheye
|
||||
@param distorted Output array of image points, 1xN/Nx1 2-channel, or vector\<Point2f\> .
|
||||
|
||||
Note that the function assumes the camera intrinsic matrix of the undistorted points to be identity.
|
||||
This means if you want to transform back points undistorted with undistortPoints() you have to
|
||||
This means if you want to transform back points undistorted with #fisheye::undistortPoints you have to
|
||||
multiply them with \f$P^{-1}\f$.
|
||||
*/
|
||||
CV_EXPORTS_W void distortPoints(InputArray undistorted, OutputArray distorted, InputArray K, InputArray D, double alpha = 0);
|
||||
@@ -3832,7 +3957,7 @@ namespace fisheye
|
||||
CV_EXPORTS_W void undistortPoints(InputArray distorted, OutputArray undistorted,
|
||||
InputArray K, InputArray D, InputArray R = noArray(), InputArray P = noArray());
|
||||
|
||||
/** @brief Computes undistortion and rectification maps for image transform by cv::remap(). If D is empty zero
|
||||
/** @brief Computes undistortion and rectification maps for image transform by #remap. If D is empty zero
|
||||
distortion is used, if R or P is empty identity matrixes are used.
|
||||
|
||||
@param K Camera intrinsic matrix \f$cameramatrix{K}\f$.
|
||||
@@ -3841,7 +3966,7 @@ namespace fisheye
|
||||
1-channel or 1x1 3-channel
|
||||
@param P New camera intrinsic matrix (3x3) or new projection matrix (3x4)
|
||||
@param size Undistorted image size.
|
||||
@param m1type Type of the first output map that can be CV_32FC1 or CV_16SC2 . See convertMaps()
|
||||
@param m1type Type of the first output map that can be CV_32FC1 or CV_16SC2 . See #convertMaps
|
||||
for details.
|
||||
@param map1 The first output map.
|
||||
@param map2 The second output map.
|
||||
@@ -3861,14 +3986,14 @@ namespace fisheye
|
||||
|
||||
The function transforms an image to compensate radial and tangential lens distortion.
|
||||
|
||||
The function is simply a combination of fisheye::initUndistortRectifyMap (with unity R ) and remap
|
||||
The function is simply a combination of #fisheye::initUndistortRectifyMap (with unity R ) and #remap
|
||||
(with bilinear interpolation). See the former function for details of the transformation being
|
||||
performed.
|
||||
|
||||
See below the results of undistortImage.
|
||||
- a\) result of undistort of perspective camera model (all possible coefficients (k_1, k_2, k_3,
|
||||
k_4, k_5, k_6) of distortion were optimized under calibration)
|
||||
- b\) result of fisheye::undistortImage of fisheye camera model (all possible coefficients (k_1, k_2,
|
||||
- b\) result of #fisheye::undistortImage of fisheye camera model (all possible coefficients (k_1, k_2,
|
||||
k_3, k_4) of fisheye distortion were optimized under calibration)
|
||||
- c\) original image was captured with fisheye lens
|
||||
|
||||
@@ -3927,6 +4052,8 @@ namespace fisheye
|
||||
are set to zeros and stay zero.
|
||||
- @ref fisheye::CALIB_FIX_PRINCIPAL_POINT The principal point is not changed during the global
|
||||
optimization. It stays at the center or at a different location specified when @ref fisheye::CALIB_USE_INTRINSIC_GUESS is set too.
|
||||
- @ref fisheye::CALIB_FIX_FOCAL_LENGTH The focal length is not changed during the global
|
||||
optimization. It is the \f$max(width,height)/\pi\f$ or the provided \f$f_x\f$, \f$f_y\f$ when @ref fisheye::CALIB_USE_INTRINSIC_GUESS is set too.
|
||||
@param criteria Termination criteria for the iterative optimization algorithm.
|
||||
*/
|
||||
CV_EXPORTS_W double calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, const Size& image_size,
|
||||
@@ -3956,7 +4083,7 @@ optimization. It stays at the center or at a different location specified when @
|
||||
horizontal or vertical direction (depending on the orientation of epipolar lines) to maximize the
|
||||
useful image area.
|
||||
@param newImageSize New image resolution after rectification. The same size should be passed to
|
||||
initUndistortRectifyMap (see the stereo_calib.cpp sample in OpenCV samples directory). When (0,0)
|
||||
#initUndistortRectifyMap (see the stereo_calib.cpp sample in OpenCV samples directory). When (0,0)
|
||||
is passed (default), it is set to the original imageSize . Setting it to larger value can help you
|
||||
preserve details in the original image, especially when there is a big radial distortion.
|
||||
@param balance Sets the new focal length in range between the min focal length and the max focal
|
||||
|
||||
@@ -16,4 +16,15 @@ PERF_TEST(Undistort, InitUndistortMap)
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST(Undistort, DISABLED_InitInverseRectificationMap)
|
||||
{
|
||||
Size size_w_h(512 + 3, 512);
|
||||
Mat k(3, 3, CV_32FC1);
|
||||
Mat d(1, 14, CV_64FC1);
|
||||
Mat dst(size_w_h, CV_32FC2);
|
||||
declare.in(k, d, WARMUP_RNG).out(dst);
|
||||
TEST_CYCLE() initInverseRectificationMap(k, d, noArray(), k, size_w_h, CV_32FC2, dst, noArray());
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1842,7 +1842,7 @@ void ChessBoardDetector::generateQuads(const cv::Mat& image_, int flags)
|
||||
if (boardIdx != parentIdx && (boardIdx < 0 || contour_child_counter[boardIdx] < contour_child_counter[parentIdx]))
|
||||
boardIdx = parentIdx;
|
||||
|
||||
contour_quads.push_back(QuadCountour(pt, parentIdx));
|
||||
contour_quads.emplace_back(pt, parentIdx);
|
||||
}
|
||||
|
||||
size_t total = contour_quads.size();
|
||||
|
||||
@@ -78,7 +78,7 @@ static void icvGetQuadrangleHypotheses(const std::vector<std::vector< cv::Point
|
||||
continue;
|
||||
}
|
||||
|
||||
quads.push_back(std::pair<float, int>(box_size, class_id));
|
||||
quads.emplace_back(box_size, class_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3924,7 +3924,7 @@ bool findChessboardCornersSB(cv::InputArray image_, cv::Size pattern_size,
|
||||
{
|
||||
meta_.create(int(board.rowCount()),int(board.colCount()),CV_8UC1);
|
||||
cv::Mat meta = meta_.getMat();
|
||||
meta = 0;
|
||||
meta.setTo(cv::Scalar::all(0));
|
||||
for(int row =0;row < meta.rows-1;++row)
|
||||
{
|
||||
for(int col=0;col< meta.cols-1;++col)
|
||||
|
||||
@@ -384,15 +384,15 @@ void CirclesGridClusterFinder::rectifyPatternPoints(const std::vector<cv::Point2
|
||||
{
|
||||
//indices of corner points in pattern
|
||||
std::vector<Point> trueIndices;
|
||||
trueIndices.push_back(Point(0, 0));
|
||||
trueIndices.push_back(Point(patternSize.width - 1, 0));
|
||||
trueIndices.emplace_back(0, 0);
|
||||
trueIndices.emplace_back(patternSize.width - 1, 0);
|
||||
if(isAsymmetricGrid)
|
||||
{
|
||||
trueIndices.push_back(Point(patternSize.width - 1, 1));
|
||||
trueIndices.push_back(Point(patternSize.width - 1, patternSize.height - 2));
|
||||
trueIndices.emplace_back(patternSize.width - 1, 1);
|
||||
trueIndices.emplace_back(patternSize.width - 1, patternSize.height - 2);
|
||||
}
|
||||
trueIndices.push_back(Point(patternSize.width - 1, patternSize.height - 1));
|
||||
trueIndices.push_back(Point(0, patternSize.height - 1));
|
||||
trueIndices.emplace_back(patternSize.width - 1, patternSize.height - 1);
|
||||
trueIndices.emplace_back(0, patternSize.height - 1);
|
||||
|
||||
std::vector<Point2f> idealPoints;
|
||||
for(size_t idx=0; idx<trueIndices.size(); idx++)
|
||||
@@ -401,11 +401,11 @@ void CirclesGridClusterFinder::rectifyPatternPoints(const std::vector<cv::Point2
|
||||
int j = trueIndices[idx].x;
|
||||
if(isAsymmetricGrid)
|
||||
{
|
||||
idealPoints.push_back(Point2f((2*j + i % 2)*squareSize, i*squareSize));
|
||||
idealPoints.emplace_back((2*j + i % 2)*squareSize, i*squareSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
idealPoints.push_back(Point2f(j*squareSize, i*squareSize));
|
||||
idealPoints.emplace_back(j*squareSize, i*squareSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,7 +477,7 @@ void Graph::addVertex(size_t id)
|
||||
{
|
||||
CV_Assert( !doesVertexExist( id ) );
|
||||
|
||||
vertices.insert(std::pair<size_t, Vertex> (id, Vertex()));
|
||||
vertices.emplace(id, Vertex());
|
||||
}
|
||||
|
||||
void Graph::addEdge(size_t id1, size_t id2)
|
||||
@@ -887,10 +887,9 @@ Mat CirclesGridFinder::rectifyGrid(Size detectedGridSize, const std::vector<Poin
|
||||
convertPointsFromHomogeneous(dstKeypointsMat, dstKeypoints);
|
||||
|
||||
warpedKeypoints.clear();
|
||||
for (size_t i = 0; i < dstKeypoints.size(); i++)
|
||||
for (auto &pt:dstKeypoints)
|
||||
{
|
||||
Point2f pt = dstKeypoints[i];
|
||||
warpedKeypoints.push_back(pt);
|
||||
warpedKeypoints.emplace_back(std::move(pt));
|
||||
}
|
||||
|
||||
return H;
|
||||
@@ -1526,35 +1525,35 @@ void CirclesGridFinder::getCornerSegments(const std::vector<std::vector<size_t>
|
||||
|
||||
//all 8 segments with one end in a corner
|
||||
std::vector<Segment> corner;
|
||||
corner.push_back(Segment(keypoints[points[1][0]], keypoints[points[0][0]]));
|
||||
corner.push_back(Segment(keypoints[points[0][0]], keypoints[points[0][1]]));
|
||||
corner.emplace_back(keypoints[points[1][0]], keypoints[points[0][0]]);
|
||||
corner.emplace_back(keypoints[points[0][0]], keypoints[points[0][1]]);
|
||||
segments.push_back(corner);
|
||||
cornerIndices.push_back(Point(0, 0));
|
||||
firstSteps.push_back(Point(1, 0));
|
||||
secondSteps.push_back(Point(0, 1));
|
||||
cornerIndices.emplace_back(0, 0);
|
||||
firstSteps.emplace_back(1, 0);
|
||||
secondSteps.emplace_back(0, 1);
|
||||
corner.clear();
|
||||
|
||||
corner.push_back(Segment(keypoints[points[0][w - 2]], keypoints[points[0][w - 1]]));
|
||||
corner.push_back(Segment(keypoints[points[0][w - 1]], keypoints[points[1][w - 1]]));
|
||||
corner.emplace_back(keypoints[points[0][w - 2]], keypoints[points[0][w - 1]]);
|
||||
corner.emplace_back(keypoints[points[0][w - 1]], keypoints[points[1][w - 1]]);
|
||||
segments.push_back(corner);
|
||||
cornerIndices.push_back(Point(w - 1, 0));
|
||||
firstSteps.push_back(Point(0, 1));
|
||||
secondSteps.push_back(Point(-1, 0));
|
||||
cornerIndices.emplace_back(w - 1, 0);
|
||||
firstSteps.emplace_back(0, 1);
|
||||
secondSteps.emplace_back(-1, 0);
|
||||
corner.clear();
|
||||
|
||||
corner.push_back(Segment(keypoints[points[h - 2][w - 1]], keypoints[points[h - 1][w - 1]]));
|
||||
corner.push_back(Segment(keypoints[points[h - 1][w - 1]], keypoints[points[h - 1][w - 2]]));
|
||||
corner.emplace_back(keypoints[points[h - 2][w - 1]], keypoints[points[h - 1][w - 1]]);
|
||||
corner.emplace_back(keypoints[points[h - 1][w - 1]], keypoints[points[h - 1][w - 2]]);
|
||||
segments.push_back(corner);
|
||||
cornerIndices.push_back(Point(w - 1, h - 1));
|
||||
firstSteps.push_back(Point(-1, 0));
|
||||
secondSteps.push_back(Point(0, -1));
|
||||
cornerIndices.emplace_back(w - 1, h - 1);
|
||||
firstSteps.emplace_back(-1, 0);
|
||||
secondSteps.emplace_back(0, -1);
|
||||
corner.clear();
|
||||
|
||||
corner.push_back(Segment(keypoints[points[h - 1][1]], keypoints[points[h - 1][0]]));
|
||||
corner.push_back(Segment(keypoints[points[h - 1][0]], keypoints[points[h - 2][0]]));
|
||||
cornerIndices.push_back(Point(0, h - 1));
|
||||
firstSteps.push_back(Point(0, -1));
|
||||
secondSteps.push_back(Point(1, 0));
|
||||
corner.emplace_back(keypoints[points[h - 1][1]], keypoints[points[h - 1][0]]);
|
||||
corner.emplace_back(keypoints[points[h - 1][0]], keypoints[points[h - 2][0]]);
|
||||
cornerIndices.emplace_back(0, h - 1);
|
||||
firstSteps.emplace_back(0, -1);
|
||||
secondSteps.emplace_back(1, 0);
|
||||
segments.push_back(corner);
|
||||
corner.clear();
|
||||
|
||||
|
||||
@@ -754,8 +754,8 @@ double cv::fisheye::calibrate(InputArrayOfArrays objectPoints, InputArrayOfArray
|
||||
IntrinsicParams currentParam;
|
||||
IntrinsicParams errors;
|
||||
|
||||
finalParam.isEstimate[0] = 1;
|
||||
finalParam.isEstimate[1] = 1;
|
||||
finalParam.isEstimate[0] = flags & CALIB_FIX_FOCAL_LENGTH ? 0 : 1;
|
||||
finalParam.isEstimate[1] = flags & CALIB_FIX_FOCAL_LENGTH ? 0 : 1;
|
||||
finalParam.isEstimate[2] = flags & CALIB_FIX_PRINCIPAL_POINT ? 0 : 1;
|
||||
finalParam.isEstimate[3] = flags & CALIB_FIX_PRINCIPAL_POINT ? 0 : 1;
|
||||
finalParam.isEstimate[4] = flags & CALIB_FIX_SKEW ? 0 : 1;
|
||||
|
||||
@@ -405,7 +405,8 @@ protected:
|
||||
|
||||
// Input should be a vector of n 2D points or a Nx2 matrix
|
||||
cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, InputArray _cameraMatrix,
|
||||
int method, double prob, double threshold, OutputArray _mask)
|
||||
int method, double prob, double threshold,
|
||||
int maxIters, OutputArray _mask)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
@@ -448,20 +449,36 @@ cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, InputArr
|
||||
|
||||
Mat E;
|
||||
if( method == RANSAC )
|
||||
createRANSACPointSetRegistrator(makePtr<EMEstimatorCallback>(), 5, threshold, prob)->run(points1, points2, E, _mask);
|
||||
createRANSACPointSetRegistrator(makePtr<EMEstimatorCallback>(), 5, threshold, prob, maxIters)->run(points1, points2, E, _mask);
|
||||
else
|
||||
createLMeDSPointSetRegistrator(makePtr<EMEstimatorCallback>(), 5, prob)->run(points1, points2, E, _mask);
|
||||
createLMeDSPointSetRegistrator(makePtr<EMEstimatorCallback>(), 5, prob, maxIters)->run(points1, points2, E, _mask);
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, InputArray _cameraMatrix,
|
||||
int method, double prob, double threshold,
|
||||
OutputArray _mask)
|
||||
{
|
||||
return cv::findEssentialMat(_points1, _points2, _cameraMatrix, method, prob, threshold, 1000, _mask);
|
||||
}
|
||||
|
||||
cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, double focal, Point2d pp,
|
||||
int method, double prob, double threshold, int maxIters, OutputArray _mask)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Mat cameraMatrix = (Mat_<double>(3,3) << focal, 0, pp.x, 0, focal, pp.y, 0, 0, 1);
|
||||
return cv::findEssentialMat(_points1, _points2, cameraMatrix, method, prob, threshold, maxIters, _mask);
|
||||
}
|
||||
|
||||
cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, double focal, Point2d pp,
|
||||
int method, double prob, double threshold, OutputArray _mask)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Mat cameraMatrix = (Mat_<double>(3,3) << focal, 0, pp.x, 0, focal, pp.y, 0, 0, 1);
|
||||
return cv::findEssentialMat(_points1, _points2, cameraMatrix, method, prob, threshold, _mask);
|
||||
return cv::findEssentialMat(_points1, _points2, cameraMatrix, method, prob, threshold, 1000, _mask);
|
||||
}
|
||||
|
||||
cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2,
|
||||
|
||||
@@ -888,7 +888,7 @@ cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2,
|
||||
if( (method & ~3) == FM_RANSAC && npoints >= 15 )
|
||||
result = createRANSACPointSetRegistrator(cb, 7, ransacReprojThreshold, confidence, maxIters)->run(m1, m2, F, _mask);
|
||||
else
|
||||
result = createLMeDSPointSetRegistrator(cb, 7, confidence)->run(m1, m2, F, _mask);
|
||||
result = createLMeDSPointSetRegistrator(cb, 7, confidence, maxIters)->run(m1, m2, F, _mask);
|
||||
}
|
||||
|
||||
if( result <= 0 )
|
||||
|
||||
@@ -65,7 +65,8 @@ int solve_deg3(double a, double b, double c, double d,
|
||||
return 3;
|
||||
}
|
||||
else {
|
||||
x0 = pow(2 * R, 1 / 3.0) - b_a_3;
|
||||
double cube_root = cv::cubeRoot(2 * R);
|
||||
x0 = cube_root - b_a_3;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -82,8 +83,15 @@ int solve_deg3(double a, double b, double c, double d,
|
||||
}
|
||||
|
||||
// D > 0, only one real root
|
||||
double AD = pow(fabs(R) + sqrt(D), 1.0 / 3.0) * (R > 0 ? 1 : (R < 0 ? -1 : 0));
|
||||
double BD = (AD == 0) ? 0 : -Q / AD;
|
||||
double AD = 0.;
|
||||
double BD = 0.;
|
||||
double R_abs = fabs(R);
|
||||
if (R_abs > DBL_EPSILON)
|
||||
{
|
||||
AD = cv::cubeRoot(R_abs + sqrt(D));
|
||||
AD = (R >= 0) ? AD : -AD;
|
||||
BD = -Q / AD;
|
||||
}
|
||||
|
||||
// Calculate the only real root
|
||||
x0 = AD + BD - b_a_3;
|
||||
|
||||
@@ -900,6 +900,86 @@ int estimateAffine3D(InputArray _from, InputArray _to,
|
||||
return createRANSACPointSetRegistrator(makePtr<Affine3DEstimatorCallback>(), 4, ransacThreshold, confidence)->run(dFrom, dTo, _out, _inliers);
|
||||
}
|
||||
|
||||
Mat estimateAffine3D(InputArray _from, InputArray _to,
|
||||
CV_OUT double* _scale, bool force_rotation)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
Mat from = _from.getMat(), to = _to.getMat();
|
||||
int count = from.checkVector(3);
|
||||
|
||||
CV_CheckGE(count, 3, "Umeyama algorithm needs at least 3 points for affine transformation estimation.");
|
||||
CV_CheckEQ(to.checkVector(3), count, "Point sets need to have the same size");
|
||||
from = from.reshape(1, count);
|
||||
to = to.reshape(1, count);
|
||||
if(from.type() != CV_64F)
|
||||
from.convertTo(from, CV_64F);
|
||||
if(to.type() != CV_64F)
|
||||
to.convertTo(to, CV_64F);
|
||||
|
||||
const double one_over_n = 1./count;
|
||||
|
||||
const auto colwise_mean = [one_over_n](const Mat& m)
|
||||
{
|
||||
Mat my;
|
||||
reduce(m, my, 0, REDUCE_SUM, CV_64F);
|
||||
return my * one_over_n;
|
||||
};
|
||||
|
||||
const auto demean = [count](const Mat& A, const Mat& mean)
|
||||
{
|
||||
Mat A_centered = Mat::zeros(count, 3, CV_64F);
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
A_centered.row(i) = A.row(i) - mean;
|
||||
}
|
||||
return A_centered;
|
||||
};
|
||||
|
||||
Mat from_mean = colwise_mean(from);
|
||||
Mat to_mean = colwise_mean(to);
|
||||
|
||||
Mat from_centered = demean(from, from_mean);
|
||||
Mat to_centered = demean(to, to_mean);
|
||||
|
||||
Mat cov = to_centered.t() * from_centered * one_over_n;
|
||||
|
||||
Mat u,d,vt;
|
||||
SVD::compute(cov, d, u, vt, SVD::MODIFY_A | SVD::FULL_UV);
|
||||
|
||||
CV_CheckGE(countNonZero(d), 2, "Points cannot be colinear");
|
||||
|
||||
Mat S = Mat::eye(3, 3, CV_64F);
|
||||
// det(d) can only ever be >=0, so we can always use this here (compared to the original formula by Umeyama)
|
||||
if (force_rotation && (determinant(u) * determinant(vt) < 0))
|
||||
{
|
||||
S.at<double>(2, 2) = -1;
|
||||
}
|
||||
Mat rmat = u*S*vt;
|
||||
|
||||
double scale = 1.0;
|
||||
if (_scale)
|
||||
{
|
||||
double var_from = 0.;
|
||||
scale = 0.;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
var_from += norm(from_centered.col(i), NORM_L2SQR);
|
||||
scale += d.at<double>(i, 0) * S.at<double>(i, i);
|
||||
}
|
||||
double inverse_var = count / var_from;
|
||||
scale *= inverse_var;
|
||||
*_scale = scale;
|
||||
}
|
||||
Mat new_to = scale * rmat * from_mean.t();
|
||||
|
||||
Mat transform;
|
||||
transform.create(3, 4, CV_64F);
|
||||
Mat r_part(transform(Rect(0, 0, 3, 3)));
|
||||
rmat.copyTo(r_part);
|
||||
transform.col(3) = to_mean.t() - new_to;
|
||||
return transform;
|
||||
}
|
||||
|
||||
int estimateTranslation3D(InputArray _from, InputArray _to,
|
||||
OutputArray _out, OutputArray _inliers,
|
||||
double ransacThreshold, double confidence)
|
||||
|
||||
@@ -334,18 +334,42 @@ bool solvePnPRansac(InputArray _opoints, InputArray _ipoints,
|
||||
|
||||
opoints_inliers.resize(npoints1);
|
||||
ipoints_inliers.resize(npoints1);
|
||||
result = solvePnP(opoints_inliers, ipoints_inliers, cameraMatrix,
|
||||
distCoeffs, rvec, tvec, useExtrinsicGuess,
|
||||
(flags == SOLVEPNP_P3P || flags == SOLVEPNP_AP3P) ? SOLVEPNP_EPNP : flags) ? 1 : -1;
|
||||
try
|
||||
{
|
||||
result = solvePnP(opoints_inliers, ipoints_inliers, cameraMatrix,
|
||||
distCoeffs, rvec, tvec, useExtrinsicGuess,
|
||||
(flags == SOLVEPNP_P3P || flags == SOLVEPNP_AP3P) ? SOLVEPNP_EPNP : flags) ? 1 : -1;
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
if (flags == SOLVEPNP_ITERATIVE &&
|
||||
npoints1 == 5 &&
|
||||
e.what() &&
|
||||
std::string(e.what()).find("DLT algorithm needs at least 6 points") != std::string::npos
|
||||
)
|
||||
{
|
||||
CV_LOG_INFO(NULL, "solvePnPRansac(): solvePnP stage to compute the final pose using points "
|
||||
"in the consensus set raised DLT 6 points exception, use result from MSS (Minimal Sample Sets) stage instead.");
|
||||
rvec = _local_model.col(0); // output rotation vector
|
||||
tvec = _local_model.col(1); // output translation vector
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// raise other exceptions
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if( result <= 0 )
|
||||
if (result <= 0)
|
||||
{
|
||||
_rvec.assign(_local_model.col(0)); // output rotation vector
|
||||
_tvec.assign(_local_model.col(1)); // output translation vector
|
||||
|
||||
if( _inliers.needed() )
|
||||
if (_inliers.needed())
|
||||
_inliers.release();
|
||||
|
||||
CV_LOG_DEBUG(NULL, "solvePnPRansac(): solvePnP stage to compute the final pose using points in the consensus set failed. Return false");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -378,7 +402,14 @@ bool solvePnPRansac( InputArray objectPoints, InputArray imagePoints,
|
||||
Ptr<usac::RansacOutput> ransac_output;
|
||||
if (usac::run(model_params, imagePoints, objectPoints, model_params->getRandomGeneratorState(),
|
||||
ransac_output, cameraMatrix, noArray(), distCoeffs, noArray())) {
|
||||
usac::saveMask(inliers, ransac_output->getInliersMask());
|
||||
if (inliers.needed()) {
|
||||
const auto &inliers_mask = ransac_output->getInliersMask();
|
||||
Mat inliers_;
|
||||
for (int i = 0; i < (int)inliers_mask.size(); i++)
|
||||
if (inliers_mask[i])
|
||||
inliers_.push_back(i);
|
||||
inliers_.copyTo(inliers);
|
||||
}
|
||||
const Mat &model = ransac_output->getModel();
|
||||
model.col(0).copyTo(rvec);
|
||||
model.col(1).copyTo(tvec);
|
||||
|
||||
@@ -1148,13 +1148,15 @@ class StereoBMImpl CV_FINAL : public StereoBM
|
||||
{
|
||||
public:
|
||||
StereoBMImpl()
|
||||
: params()
|
||||
{
|
||||
params = StereoBMParams();
|
||||
// nothing
|
||||
}
|
||||
|
||||
StereoBMImpl( int _numDisparities, int _SADWindowSize )
|
||||
: params(_numDisparities, _SADWindowSize)
|
||||
{
|
||||
params = StereoBMParams(_numDisparities, _SADWindowSize);
|
||||
// nothing
|
||||
}
|
||||
|
||||
void compute( InputArray leftarr, InputArray rightarr, OutputArray disparr ) CV_OVERRIDE
|
||||
|
||||
@@ -2186,19 +2186,21 @@ class StereoSGBMImpl CV_FINAL : public StereoSGBM
|
||||
{
|
||||
public:
|
||||
StereoSGBMImpl()
|
||||
: params()
|
||||
{
|
||||
params = StereoSGBMParams();
|
||||
// nothing
|
||||
}
|
||||
|
||||
StereoSGBMImpl( int _minDisparity, int _numDisparities, int _SADWindowSize,
|
||||
int _P1, int _P2, int _disp12MaxDiff, int _preFilterCap,
|
||||
int _uniquenessRatio, int _speckleWindowSize, int _speckleRange,
|
||||
int _mode )
|
||||
: params(_minDisparity, _numDisparities, _SADWindowSize,
|
||||
_P1, _P2, _disp12MaxDiff, _preFilterCap,
|
||||
_uniquenessRatio, _speckleWindowSize, _speckleRange,
|
||||
_mode)
|
||||
{
|
||||
params = StereoSGBMParams( _minDisparity, _numDisparities, _SADWindowSize,
|
||||
_P1, _P2, _disp12MaxDiff, _preFilterCap,
|
||||
_uniquenessRatio, _speckleWindowSize, _speckleRange,
|
||||
_mode );
|
||||
// nothing
|
||||
}
|
||||
|
||||
void compute( InputArray leftarr, InputArray rightarr, OutputArray disparr ) CV_OVERRIDE
|
||||
|
||||
@@ -164,6 +164,125 @@ void initUndistortRectifyMap( InputArray _cameraMatrix, InputArray _distCoeffs,
|
||||
fx, fy, k1, k2, p1, p2, k3, k4, k5, k6, s1, s2, s3, s4));
|
||||
}
|
||||
|
||||
void initInverseRectificationMap( InputArray _cameraMatrix, InputArray _distCoeffs,
|
||||
InputArray _matR, InputArray _newCameraMatrix,
|
||||
const Size& size, int m1type, OutputArray _map1, OutputArray _map2 )
|
||||
{
|
||||
// Parameters
|
||||
Mat cameraMatrix = _cameraMatrix.getMat(), distCoeffs = _distCoeffs.getMat();
|
||||
Mat matR = _matR.getMat(), newCameraMatrix = _newCameraMatrix.getMat();
|
||||
|
||||
// Check m1type validity
|
||||
if( m1type <= 0 )
|
||||
m1type = CV_16SC2;
|
||||
CV_Assert( m1type == CV_16SC2 || m1type == CV_32FC1 || m1type == CV_32FC2 );
|
||||
|
||||
// Init Maps
|
||||
_map1.create( size, m1type );
|
||||
Mat map1 = _map1.getMat(), map2;
|
||||
if( m1type != CV_32FC2 )
|
||||
{
|
||||
_map2.create( size, m1type == CV_16SC2 ? CV_16UC1 : CV_32FC1 );
|
||||
map2 = _map2.getMat();
|
||||
}
|
||||
else {
|
||||
_map2.release();
|
||||
}
|
||||
|
||||
// Init camera intrinsics
|
||||
Mat_<double> A = Mat_<double>(cameraMatrix), Ar;
|
||||
if( !newCameraMatrix.empty() )
|
||||
Ar = Mat_<double>(newCameraMatrix);
|
||||
else
|
||||
Ar = getDefaultNewCameraMatrix( A, size, true );
|
||||
CV_Assert( A.size() == Size(3,3) );
|
||||
CV_Assert( Ar.size() == Size(3,3) || Ar.size() == Size(4, 3));
|
||||
|
||||
// Init rotation matrix
|
||||
Mat_<double> R = Mat_<double>::eye(3, 3);
|
||||
if( !matR.empty() )
|
||||
{
|
||||
R = Mat_<double>(matR);
|
||||
//Note, do not inverse
|
||||
}
|
||||
CV_Assert( Size(3,3) == R.size() );
|
||||
|
||||
// Init distortion vector
|
||||
if( !distCoeffs.empty() ){
|
||||
distCoeffs = Mat_<double>(distCoeffs);
|
||||
|
||||
// Fix distortion vector orientation
|
||||
if( distCoeffs.rows != 1 && !distCoeffs.isContinuous() ) {
|
||||
distCoeffs = distCoeffs.t();
|
||||
}
|
||||
}
|
||||
|
||||
// Validate distortion vector size
|
||||
CV_Assert( distCoeffs.empty() || // Empty allows cv::undistortPoints to skip distortion
|
||||
distCoeffs.size() == Size(1, 4) || distCoeffs.size() == Size(4, 1) ||
|
||||
distCoeffs.size() == Size(1, 5) || distCoeffs.size() == Size(5, 1) ||
|
||||
distCoeffs.size() == Size(1, 8) || distCoeffs.size() == Size(8, 1) ||
|
||||
distCoeffs.size() == Size(1, 12) || distCoeffs.size() == Size(12, 1) ||
|
||||
distCoeffs.size() == Size(1, 14) || distCoeffs.size() == Size(14, 1));
|
||||
|
||||
// Create objectPoints
|
||||
std::vector<cv::Point2i> p2i_objPoints;
|
||||
std::vector<cv::Point2f> p2f_objPoints;
|
||||
for (int r = 0; r < size.height; r++)
|
||||
{
|
||||
for (int c = 0; c < size.width; c++)
|
||||
{
|
||||
p2i_objPoints.push_back(cv::Point2i(c, r));
|
||||
p2f_objPoints.push_back(cv::Point2f(static_cast<float>(c), static_cast<float>(r)));
|
||||
}
|
||||
}
|
||||
|
||||
// Undistort
|
||||
std::vector<cv::Point2f> p2f_objPoints_undistorted;
|
||||
undistortPoints(
|
||||
p2f_objPoints,
|
||||
p2f_objPoints_undistorted,
|
||||
A,
|
||||
distCoeffs,
|
||||
cv::Mat::eye(cv::Size(3, 3), CV_64FC1), // R
|
||||
cv::Mat::eye(cv::Size(3, 3), CV_64FC1) // P = New K
|
||||
);
|
||||
|
||||
// Rectify
|
||||
std::vector<cv::Point2f> p2f_sourcePoints_pinHole;
|
||||
perspectiveTransform(
|
||||
p2f_objPoints_undistorted,
|
||||
p2f_sourcePoints_pinHole,
|
||||
R
|
||||
);
|
||||
|
||||
// Project points back to camera coordinates.
|
||||
std::vector<cv::Point2f> p2f_sourcePoints;
|
||||
undistortPoints(
|
||||
p2f_sourcePoints_pinHole,
|
||||
p2f_sourcePoints,
|
||||
cv::Mat::eye(cv::Size(3, 3), CV_32FC1), // K
|
||||
cv::Mat::zeros(cv::Size(1, 4), CV_32FC1), // Distortion
|
||||
cv::Mat::eye(cv::Size(3, 3), CV_32FC1), // R
|
||||
Ar // New K
|
||||
);
|
||||
|
||||
// Copy to map
|
||||
if (m1type == CV_16SC2) {
|
||||
for (size_t i=0; i < p2i_objPoints.size(); i++) {
|
||||
map1.at<Vec2s>(p2i_objPoints[i].y, p2i_objPoints[i].x) = Vec2s(saturate_cast<short>(p2f_sourcePoints[i].x), saturate_cast<short>(p2f_sourcePoints[i].y));
|
||||
}
|
||||
} else if (m1type == CV_32FC2) {
|
||||
for (size_t i=0; i < p2i_objPoints.size(); i++) {
|
||||
map1.at<Vec2f>(p2i_objPoints[i].y, p2i_objPoints[i].x) = Vec2f(p2f_sourcePoints[i]);
|
||||
}
|
||||
} else { // m1type == CV_32FC1
|
||||
for (size_t i=0; i < p2i_objPoints.size(); i++) {
|
||||
map1.at<float>(p2i_objPoints[i].y, p2i_objPoints[i].x) = p2f_sourcePoints[i].x;
|
||||
map2.at<float>(p2i_objPoints[i].y, p2i_objPoints[i].x) = p2f_sourcePoints[i].y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void undistort( InputArray _src, OutputArray _dst, InputArray _cameraMatrix,
|
||||
InputArray _distCoeffs, InputArray _newCameraMatrix )
|
||||
|
||||
@@ -408,10 +408,11 @@ int mergePoints (InputArray pts1_, InputArray pts2_, Mat &pts, bool ispnp) {
|
||||
void saveMask (OutputArray mask, const std::vector<bool> &inliers_mask) {
|
||||
if (mask.needed()) {
|
||||
const int points_size = (int) inliers_mask.size();
|
||||
mask.create(points_size, 1, CV_8U);
|
||||
auto * maskptr = mask.getMat().ptr<uchar>();
|
||||
Mat tmp_mask(points_size, 1, CV_8U);
|
||||
auto * maskptr = tmp_mask.ptr<uchar>();
|
||||
for (int i = 0; i < points_size; i++)
|
||||
maskptr[i] = (uchar) inliers_mask[i];
|
||||
tmp_mask.copyTo(mask);
|
||||
}
|
||||
}
|
||||
void setParameters (Ptr<Model> ¶ms, EstimationMethod estimator, const UsacParams &usac_params,
|
||||
@@ -538,23 +539,26 @@ Mat findEssentialMat (InputArray points1, InputArray points2, InputArray cameraM
|
||||
bool solvePnPRansac( InputArray objectPoints, InputArray imagePoints,
|
||||
InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec,
|
||||
bool /*useExtrinsicGuess*/, int max_iters, float thr, double conf,
|
||||
OutputArray mask, int method) {
|
||||
OutputArray inliers, int method) {
|
||||
Ptr<Model> params;
|
||||
setParameters(method, params, cameraMatrix.empty() ? EstimationMethod ::P6P : EstimationMethod ::P3P,
|
||||
thr, max_iters, conf, mask.needed());
|
||||
thr, max_iters, conf, inliers.needed());
|
||||
Ptr<RansacOutput> ransac_output;
|
||||
if (run(params, imagePoints, objectPoints, params->getRandomGeneratorState(),
|
||||
ransac_output, cameraMatrix, noArray(), distCoeffs, noArray())) {
|
||||
saveMask(mask, ransac_output->getInliersMask());
|
||||
if (inliers.needed()) {
|
||||
const auto &inliers_mask = ransac_output->getInliersMask();
|
||||
Mat inliers_;
|
||||
for (int i = 0; i < (int)inliers_mask.size(); i++)
|
||||
if (inliers_mask[i])
|
||||
inliers_.push_back(i);
|
||||
inliers_.copyTo(inliers);
|
||||
}
|
||||
const Mat &model = ransac_output->getModel();
|
||||
model.col(0).copyTo(rvec);
|
||||
model.col(1).copyTo(tvec);
|
||||
return true;
|
||||
}
|
||||
if (mask.needed()){
|
||||
mask.create(std::max(objectPoints.getMat().rows, objectPoints.getMat().cols), 1, CV_8U);
|
||||
mask.setTo(Scalar::all(0));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,4 +201,25 @@ TEST(Calib3d_EstimateAffine3D, regression_16007)
|
||||
EXPECT_EQ(1, res);
|
||||
}
|
||||
|
||||
TEST(Calib3d_EstimateAffine3D, umeyama_3_pt)
|
||||
{
|
||||
std::vector<cv::Vec3d> points = {{{0.80549149, 0.8225781, 0.79949521},
|
||||
{0.28906756, 0.57158557, 0.9864789},
|
||||
{0.58266182, 0.65474983, 0.25078834}}};
|
||||
cv::Mat R = (cv::Mat_<double>(3,3) << 0.9689135, -0.0232753, 0.2463025,
|
||||
0.0236362, 0.9997195, 0.0014915,
|
||||
-0.2462682, 0.0043765, 0.9691918);
|
||||
cv::Vec3d t(1., 2., 3.);
|
||||
cv::Affine3d transform(R, t);
|
||||
std::vector<cv::Vec3d> transformed_points(points.size());
|
||||
std::transform(points.begin(), points.end(), transformed_points.begin(), [transform](const cv::Vec3d v){return transform * v;});
|
||||
double scale;
|
||||
cv::Mat trafo_est = estimateAffine3D(points, transformed_points, &scale);
|
||||
Mat R_est(trafo_est(Rect(0, 0, 3, 3)));
|
||||
EXPECT_LE(cvtest::norm(R_est, R, NORM_INF), 1e-6);
|
||||
Vec3d t_est = trafo_est.col(3);
|
||||
EXPECT_LE(cvtest::norm(t_est, t, NORM_INF), 1e-6);
|
||||
EXPECT_NEAR(scale, 1.0, 1e-6);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -345,7 +345,7 @@ TEST_F(fisheyeTest, Calibration)
|
||||
std::vector<std::vector<cv::Point2d> > imagePoints(n_images);
|
||||
std::vector<std::vector<cv::Point3d> > objectPoints(n_images);
|
||||
|
||||
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
const std::string folder = combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ);
|
||||
CV_Assert(fs_left.isOpened());
|
||||
for(int i = 0; i < n_images; ++i)
|
||||
@@ -373,6 +373,53 @@ TEST_F(fisheyeTest, Calibration)
|
||||
EXPECT_MAT_NEAR(theD, this->D, 1e-10);
|
||||
}
|
||||
|
||||
TEST_F(fisheyeTest, CalibrationWithFixedFocalLength)
|
||||
{
|
||||
const int n_images = 34;
|
||||
|
||||
std::vector<std::vector<cv::Point2d> > imagePoints(n_images);
|
||||
std::vector<std::vector<cv::Point3d> > objectPoints(n_images);
|
||||
|
||||
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ);
|
||||
CV_Assert(fs_left.isOpened());
|
||||
for(int i = 0; i < n_images; ++i)
|
||||
fs_left[cv::format("image_%d", i )] >> imagePoints[i];
|
||||
fs_left.release();
|
||||
|
||||
cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ);
|
||||
CV_Assert(fs_object.isOpened());
|
||||
for(int i = 0; i < n_images; ++i)
|
||||
fs_object[cv::format("image_%d", i )] >> objectPoints[i];
|
||||
fs_object.release();
|
||||
|
||||
int flag = 0;
|
||||
flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
|
||||
flag |= cv::fisheye::CALIB_CHECK_COND;
|
||||
flag |= cv::fisheye::CALIB_FIX_SKEW;
|
||||
flag |= cv::fisheye::CALIB_FIX_FOCAL_LENGTH;
|
||||
flag |= cv::fisheye::CALIB_USE_INTRINSIC_GUESS;
|
||||
|
||||
cv::Matx33d theK = this->K;
|
||||
const cv::Matx33d newK(
|
||||
558.478088, 0.000000, 620.458461,
|
||||
0.000000, 560.506767, 381.939362,
|
||||
0.000000, 0.000000, 1.000000);
|
||||
|
||||
cv::Vec4d theD;
|
||||
const cv::Vec4d newD(-0.001461, -0.003298, 0.006057, -0.003742);
|
||||
|
||||
cv::fisheye::calibrate(objectPoints, imagePoints, imageSize, theK, theD,
|
||||
cv::noArray(), cv::noArray(), flag, cv::TermCriteria(3, 20, 1e-6));
|
||||
|
||||
// ensure that CALIB_FIX_FOCAL_LENGTH works and focal lenght has not changed
|
||||
EXPECT_EQ(theK(0,0), K(0,0));
|
||||
EXPECT_EQ(theK(1,1), K(1,1));
|
||||
|
||||
EXPECT_MAT_NEAR(theK, newK, 1e-6);
|
||||
EXPECT_MAT_NEAR(theD, newD, 1e-6);
|
||||
}
|
||||
|
||||
TEST_F(fisheyeTest, Homography)
|
||||
{
|
||||
const int n_images = 1;
|
||||
@@ -380,7 +427,7 @@ TEST_F(fisheyeTest, Homography)
|
||||
std::vector<std::vector<cv::Point2d> > imagePoints(n_images);
|
||||
std::vector<std::vector<cv::Point3d> > objectPoints(n_images);
|
||||
|
||||
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
const std::string folder = combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ);
|
||||
CV_Assert(fs_left.isOpened());
|
||||
for(int i = 0; i < n_images; ++i)
|
||||
@@ -498,7 +545,7 @@ TEST_F(fisheyeTest, stereoRectify)
|
||||
"For the purpose of continuity the following should be true: cv::CALIB_ZERO_DISPARITY == cv::fisheye::CALIB_ZERO_DISPARITY"
|
||||
);
|
||||
|
||||
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
const std::string folder = combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
|
||||
cv::Size calibration_size = this->imageSize, requested_size = calibration_size;
|
||||
cv::Matx33d K1 = this->K, K2 = K1;
|
||||
@@ -599,7 +646,7 @@ TEST_F(fisheyeTest, stereoCalibrate)
|
||||
{
|
||||
const int n_images = 34;
|
||||
|
||||
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
const std::string folder = combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
|
||||
std::vector<std::vector<cv::Point2d> > leftPoints(n_images);
|
||||
std::vector<std::vector<cv::Point2d> > rightPoints(n_images);
|
||||
@@ -666,7 +713,7 @@ TEST_F(fisheyeTest, stereoCalibrateFixIntrinsic)
|
||||
{
|
||||
const int n_images = 34;
|
||||
|
||||
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
const std::string folder = combine(datasets_repository_path, "calib-3_stereo_from_JY");
|
||||
|
||||
std::vector<std::vector<cv::Point2d> > leftPoints(n_images);
|
||||
std::vector<std::vector<cv::Point2d> > rightPoints(n_images);
|
||||
@@ -822,6 +869,7 @@ const cv::Matx33d fisheyeTest::K(558.478087865323, 0, 620.45851536
|
||||
|
||||
const cv::Vec4d fisheyeTest::D(-0.0014613319981768, -0.00329861110580401, 0.00605760088590183, -0.00374209380722371);
|
||||
|
||||
|
||||
const cv::Matx33d fisheyeTest::R ( 9.9756700084424932e-01, 6.9698277640183867e-02, 1.4929569991321144e-03,
|
||||
-6.9711825162322980e-02, 9.9748249845531767e-01, 1.2997180766418455e-02,
|
||||
-5.8331736398316541e-04,-1.3069635393884985e-02, 9.9991441852366736e-01);
|
||||
|
||||
@@ -837,6 +837,43 @@ TEST(Calib3d_SolvePnPRansac, double_support)
|
||||
EXPECT_LE(cvtest::norm(t, Mat_<double>(tF), NORM_INF), 1e-3);
|
||||
}
|
||||
|
||||
TEST(Calib3d_SolvePnPRansac, bad_input_points_19253)
|
||||
{
|
||||
// with this specific data
|
||||
// when computing the final pose using points in the consensus set with SOLVEPNP_ITERATIVE and solvePnP()
|
||||
// an exception is thrown from solvePnP because there are 5 non-coplanar 3D points and the DLT algorithm needs at least 6 non-coplanar 3D points
|
||||
// with PR #19253 we choose to return true, with the pose estimated from the MSS stage instead of throwing the exception
|
||||
|
||||
float pts2d_[] = {
|
||||
-5.38358629e-01f, -5.09638414e-02f,
|
||||
-5.07192254e-01f, -2.20743284e-01f,
|
||||
-5.43107152e-01f, -4.90474701e-02f,
|
||||
-5.54325163e-01f, -1.86715424e-01f,
|
||||
-5.59334219e-01f, -4.01909500e-02f,
|
||||
-5.43504596e-01f, -4.61776406e-02f
|
||||
};
|
||||
Mat pts2d(6, 2, CV_32FC1, pts2d_);
|
||||
|
||||
float pts3d_[] = {
|
||||
-3.01153604e-02f, -1.55665115e-01f, 4.50000018e-01f,
|
||||
4.27827090e-01f, 4.28645730e-01f, 1.08600008e+00f,
|
||||
-3.14165242e-02f, -1.52656138e-01f, 4.50000018e-01f,
|
||||
-1.46217480e-01f, 5.57961613e-02f, 7.17000008e-01f,
|
||||
-4.89348806e-02f, -1.38795510e-01f, 4.47000027e-01f,
|
||||
-3.13065052e-02f, -1.52636901e-01f, 4.51000035e-01f
|
||||
};
|
||||
Mat pts3d(6, 3, CV_32FC1, pts3d_);
|
||||
|
||||
Mat camera_mat = Mat::eye(3, 3, CV_64FC1);
|
||||
Mat rvec, tvec;
|
||||
vector<int> inliers;
|
||||
|
||||
// solvePnPRansac will return true with 5 inliers, which means the result is from MSS stage.
|
||||
bool result = solvePnPRansac(pts3d, pts2d, camera_mat, noArray(), rvec, tvec, false, 100, 4.f / 460.f, 0.99, inliers);
|
||||
EXPECT_EQ(inliers.size(), size_t(5));
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
|
||||
TEST(Calib3d_SolvePnP, input_type)
|
||||
{
|
||||
Matx33d intrinsics(5.4794130238156129e+002, 0., 2.9835545700043139e+002, 0.,
|
||||
|
||||
@@ -719,11 +719,281 @@ double CV_InitUndistortRectifyMapTest::get_success_error_level( int /*test_case_
|
||||
return 8;
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
class CV_InitInverseRectificationMapTest : public cvtest::ArrayTest
|
||||
{
|
||||
public:
|
||||
CV_InitInverseRectificationMapTest();
|
||||
protected:
|
||||
int prepare_test_case (int test_case_idx);
|
||||
void prepare_to_validation( int test_case_idx );
|
||||
void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
|
||||
double get_success_error_level( int test_case_idx, int i, int j );
|
||||
void run_func();
|
||||
|
||||
private:
|
||||
static const int MAX_X = 1024;
|
||||
static const int MAX_Y = 1024;
|
||||
bool zero_new_cam;
|
||||
bool zero_distortion;
|
||||
bool zero_R;
|
||||
|
||||
cv::Size img_size;
|
||||
int map_type;
|
||||
};
|
||||
|
||||
CV_InitInverseRectificationMapTest::CV_InitInverseRectificationMapTest()
|
||||
{
|
||||
test_array[INPUT].push_back(NULL); // camera matrix
|
||||
test_array[INPUT].push_back(NULL); // distortion coeffs
|
||||
test_array[INPUT].push_back(NULL); // R matrix
|
||||
test_array[INPUT].push_back(NULL); // new camera matrix
|
||||
test_array[OUTPUT].push_back(NULL); // inverse rectified mapx
|
||||
test_array[OUTPUT].push_back(NULL); // inverse rectified mapy
|
||||
test_array[REF_OUTPUT].push_back(NULL);
|
||||
test_array[REF_OUTPUT].push_back(NULL);
|
||||
|
||||
zero_distortion = zero_new_cam = zero_R = false;
|
||||
map_type = 0;
|
||||
}
|
||||
|
||||
void CV_InitInverseRectificationMapTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
|
||||
{
|
||||
cvtest::ArrayTest::get_test_array_types_and_sizes(test_case_idx,sizes,types);
|
||||
RNG& rng = ts->get_rng();
|
||||
//rng.next();
|
||||
|
||||
map_type = CV_32F;
|
||||
types[OUTPUT][0] = types[OUTPUT][1] = types[REF_OUTPUT][0] = types[REF_OUTPUT][1] = map_type;
|
||||
|
||||
img_size.width = cvtest::randInt(rng) % MAX_X + 1;
|
||||
img_size.height = cvtest::randInt(rng) % MAX_Y + 1;
|
||||
|
||||
types[INPUT][0] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
|
||||
types[INPUT][1] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
|
||||
types[INPUT][2] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
|
||||
types[INPUT][3] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
|
||||
|
||||
sizes[OUTPUT][0] = sizes[OUTPUT][1] = sizes[REF_OUTPUT][0] = sizes[REF_OUTPUT][1] = img_size;
|
||||
sizes[INPUT][0] = sizes[INPUT][2] = sizes[INPUT][3] = cvSize(3,3);
|
||||
|
||||
Size dsize;
|
||||
|
||||
if (cvtest::randInt(rng)%2)
|
||||
{
|
||||
if (cvtest::randInt(rng)%2)
|
||||
{
|
||||
dsize = Size(1,4);
|
||||
}
|
||||
else
|
||||
{
|
||||
dsize = Size(1,5);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cvtest::randInt(rng)%2)
|
||||
{
|
||||
dsize = Size(4,1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dsize = Size(5,1);
|
||||
}
|
||||
}
|
||||
sizes[INPUT][1] = dsize;
|
||||
}
|
||||
|
||||
|
||||
int CV_InitInverseRectificationMapTest::prepare_test_case(int test_case_idx)
|
||||
{
|
||||
RNG& rng = ts->get_rng();
|
||||
int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
|
||||
|
||||
if (code <= 0)
|
||||
return code;
|
||||
|
||||
int dist_size = test_mat[INPUT][1].cols > test_mat[INPUT][1].rows ? test_mat[INPUT][1].cols : test_mat[INPUT][1].rows;
|
||||
double cam[9] = {0,0,0,0,0,0,0,0,1};
|
||||
vector<double> dist(dist_size);
|
||||
vector<double> new_cam(test_mat[INPUT][3].cols * test_mat[INPUT][3].rows);
|
||||
|
||||
Mat _camera(3,3,CV_64F,cam);
|
||||
Mat _distort(test_mat[INPUT][1].size(),CV_64F,&dist[0]);
|
||||
Mat _new_cam(test_mat[INPUT][3].size(),CV_64F,&new_cam[0]);
|
||||
|
||||
//Generating camera matrix
|
||||
double sz = MAX(img_size.width,img_size.height);
|
||||
double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7;
|
||||
cam[2] = (img_size.width - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
|
||||
cam[5] = (img_size.height - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
|
||||
cam[0] = sz/(0.9 - cvtest::randReal(rng)*0.6);
|
||||
cam[4] = aspect_ratio*cam[0];
|
||||
|
||||
//Generating distortion coeffs
|
||||
dist[0] = cvtest::randReal(rng)*0.06 - 0.03;
|
||||
dist[1] = cvtest::randReal(rng)*0.06 - 0.03;
|
||||
if( dist[0]*dist[1] > 0 )
|
||||
dist[1] = -dist[1];
|
||||
if( cvtest::randInt(rng)%4 != 0 )
|
||||
{
|
||||
dist[2] = cvtest::randReal(rng)*0.004 - 0.002;
|
||||
dist[3] = cvtest::randReal(rng)*0.004 - 0.002;
|
||||
if (dist_size > 4)
|
||||
dist[4] = cvtest::randReal(rng)*0.004 - 0.002;
|
||||
}
|
||||
else
|
||||
{
|
||||
dist[2] = dist[3] = 0;
|
||||
if (dist_size > 4)
|
||||
dist[4] = 0;
|
||||
}
|
||||
|
||||
//Generating new camera matrix
|
||||
_new_cam = Scalar::all(0);
|
||||
new_cam[8] = 1;
|
||||
|
||||
// If P == K
|
||||
//new_cam[0] = cam[0];
|
||||
//new_cam[4] = cam[4];
|
||||
//new_cam[2] = cam[2];
|
||||
//new_cam[5] = cam[5];
|
||||
|
||||
// If P != K
|
||||
new_cam[0] = cam[0] + (cvtest::randReal(rng) - (double)0.5)*0.2*cam[0]; //10%
|
||||
new_cam[4] = cam[4] + (cvtest::randReal(rng) - (double)0.5)*0.2*cam[4]; //10%
|
||||
new_cam[2] = cam[2] + (cvtest::randReal(rng) - (double)0.5)*0.3*img_size.width; //15%
|
||||
new_cam[5] = cam[5] + (cvtest::randReal(rng) - (double)0.5)*0.3*img_size.height; //15%
|
||||
|
||||
//Generating R matrix
|
||||
Mat _rot(3,3,CV_64F);
|
||||
Mat rotation(1,3,CV_64F);
|
||||
rotation.at<double>(0) = CV_PI/8*(cvtest::randReal(rng) - (double)0.5); // phi
|
||||
rotation.at<double>(1) = CV_PI/8*(cvtest::randReal(rng) - (double)0.5); // ksi
|
||||
rotation.at<double>(2) = CV_PI/3*(cvtest::randReal(rng) - (double)0.5); //khi
|
||||
cvtest::Rodrigues(rotation, _rot);
|
||||
|
||||
//cvSetIdentity(_rot);
|
||||
//copying data
|
||||
cvtest::convert( _camera, test_mat[INPUT][0], test_mat[INPUT][0].type());
|
||||
cvtest::convert( _distort, test_mat[INPUT][1], test_mat[INPUT][1].type());
|
||||
cvtest::convert( _rot, test_mat[INPUT][2], test_mat[INPUT][2].type());
|
||||
cvtest::convert( _new_cam, test_mat[INPUT][3], test_mat[INPUT][3].type());
|
||||
|
||||
zero_distortion = (cvtest::randInt(rng)%2) == 0 ? false : true;
|
||||
zero_new_cam = (cvtest::randInt(rng)%2) == 0 ? false : true;
|
||||
zero_R = (cvtest::randInt(rng)%2) == 0 ? false : true;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
void CV_InitInverseRectificationMapTest::prepare_to_validation(int/* test_case_idx*/)
|
||||
{
|
||||
// Configure Parameters
|
||||
Mat _a0 = test_mat[INPUT][0];
|
||||
Mat _d0 = zero_distortion ? cv::Mat() : test_mat[INPUT][1];
|
||||
Mat _R0 = zero_R ? cv::Mat() : test_mat[INPUT][2];
|
||||
Mat _new_cam0 = zero_new_cam ? test_mat[INPUT][0] : test_mat[INPUT][3];
|
||||
Mat _mapx(img_size, CV_32F), _mapy(img_size, CV_32F);
|
||||
|
||||
double a[9], d[5]={0., 0., 0., 0. , 0.}, R[9]={1., 0., 0., 0., 1., 0., 0., 0., 1.}, a1[9];
|
||||
Mat _a(3, 3, CV_64F, a), _a1(3, 3, CV_64F, a1);
|
||||
Mat _d(_d0.rows,_d0.cols, CV_MAKETYPE(CV_64F,_d0.channels()),d);
|
||||
Mat _R(3, 3, CV_64F, R);
|
||||
double fx, fy, cx, cy, ifx, ify, cxn, cyn;
|
||||
|
||||
// Camera matrix
|
||||
CV_Assert(_a0.size() == Size(3, 3));
|
||||
_a0.convertTo(_a, CV_64F);
|
||||
if( !_new_cam0.empty() )
|
||||
{
|
||||
CV_Assert(_new_cam0.size() == Size(3, 3));
|
||||
_new_cam0.convertTo(_a1, CV_64F);
|
||||
}
|
||||
else
|
||||
{
|
||||
_a.copyTo(_a1);
|
||||
}
|
||||
|
||||
// Distortion
|
||||
CV_Assert(_d0.empty() ||
|
||||
_d0.size() == Size(5, 1) ||
|
||||
_d0.size() == Size(1, 5) ||
|
||||
_d0.size() == Size(4, 1) ||
|
||||
_d0.size() == Size(1, 4));
|
||||
if( !_d0.empty() )
|
||||
_d0.convertTo(_d, CV_64F);
|
||||
|
||||
// Rotation
|
||||
if( !_R0.empty() )
|
||||
{
|
||||
CV_Assert(_R0.size() == Size(3, 3));
|
||||
Mat tmp;
|
||||
_R0.convertTo(_R, CV_64F);
|
||||
}
|
||||
|
||||
// Copy camera matrix
|
||||
fx = a[0]; fy = a[4]; cx = a[2]; cy = a[5];
|
||||
|
||||
// Copy new camera matrix
|
||||
ifx = a1[0]; ify = a1[4]; cxn = a1[2]; cyn = a1[5];
|
||||
|
||||
// Undistort
|
||||
for( int v = 0; v < img_size.height; v++ )
|
||||
{
|
||||
for( int u = 0; u < img_size.width; u++ )
|
||||
{
|
||||
// Convert from image to pin-hole coordinates
|
||||
double x = (u - cx)/fx;
|
||||
double y = (v - cy)/fy;
|
||||
|
||||
// Undistort
|
||||
double x2 = x*x, y2 = y*y;
|
||||
double r2 = x2 + y2;
|
||||
double cdist = 1./(1. + (d[0] + (d[1] + d[4]*r2)*r2)*r2); // (1. + (d[5] + (d[6] + d[7]*r2)*r2)*r2) == 1 as d[5-7]=0;
|
||||
double x_ = (x - (d[2]*2.*x*y + d[3]*(r2 + 2.*x2)))*cdist;
|
||||
double y_ = (y - (d[3]*2.*x*y + d[2]*(r2 + 2.*y2)))*cdist;
|
||||
|
||||
// Rectify
|
||||
double X = R[0]*x_ + R[1]*y_ + R[2];
|
||||
double Y = R[3]*x_ + R[4]*y_ + R[5];
|
||||
double Z = R[6]*x_ + R[7]*y_ + R[8];
|
||||
double x__ = X/Z;
|
||||
double y__ = Y/Z;
|
||||
|
||||
// Convert from pin-hole to image coordinates
|
||||
_mapy.at<float>(v, u) = (float)(y__*ify + cyn);
|
||||
_mapx.at<float>(v, u) = (float)(x__*ifx + cxn);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert
|
||||
_mapx.convertTo(test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].type());
|
||||
_mapy.convertTo(test_mat[REF_OUTPUT][1], test_mat[REF_OUTPUT][0].type());
|
||||
}
|
||||
|
||||
void CV_InitInverseRectificationMapTest::run_func()
|
||||
{
|
||||
cv::Mat camera_mat = test_mat[INPUT][0];
|
||||
cv::Mat dist = zero_distortion ? cv::Mat() : test_mat[INPUT][1];
|
||||
cv::Mat R = zero_R ? cv::Mat() : test_mat[INPUT][2];
|
||||
cv::Mat new_cam = zero_new_cam ? cv::Mat() : test_mat[INPUT][3];
|
||||
cv::Mat& mapx = test_mat[OUTPUT][0], &mapy = test_mat[OUTPUT][1];
|
||||
cv::initInverseRectificationMap(camera_mat,dist,R,new_cam,img_size,map_type,mapx,mapy);
|
||||
}
|
||||
|
||||
double CV_InitInverseRectificationMapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST(Calib3d_DefaultNewCameraMatrix, accuracy) { CV_DefaultNewCameraMatrixTest test; test.safe_run(); }
|
||||
TEST(Calib3d_UndistortPoints, accuracy) { CV_UndistortPointsTest test; test.safe_run(); }
|
||||
TEST(Calib3d_InitUndistortRectifyMap, accuracy) { CV_InitUndistortRectifyMapTest test; test.safe_run(); }
|
||||
TEST(DISABLED_Calib3d_InitInverseRectificationMap, accuracy) { CV_InitInverseRectificationMapTest test; test.safe_run(); }
|
||||
|
||||
////////////////////////////// undistort /////////////////////////////////
|
||||
|
||||
@@ -1537,4 +1807,78 @@ TEST(Calib3d_initUndistortRectifyMap, regression_14467)
|
||||
EXPECT_LE(cvtest::norm(dst, mesh_uv, NORM_INF), 1e-3);
|
||||
}
|
||||
|
||||
TEST(Calib3d_initInverseRectificationMap, regression_20165)
|
||||
{
|
||||
Size size_w_h(1280, 800);
|
||||
Mat dst(size_w_h, CV_32FC2); // Reference for validation
|
||||
Mat mapxy; // Output of initInverseRectificationMap()
|
||||
|
||||
// Camera Matrix
|
||||
double k[9]={
|
||||
1.5393951443032472e+03, 0., 6.7491727003047140e+02,
|
||||
0., 1.5400748240626747e+03, 5.1226968329123963e+02,
|
||||
0., 0., 1.
|
||||
};
|
||||
Mat _K(3, 3, CV_64F, k);
|
||||
|
||||
// Distortion
|
||||
// double d[5]={0,0,0,0,0}; // Zero Distortion
|
||||
double d[5]={ // Non-zero distortion
|
||||
-3.4134571357400023e-03, 2.9733267766101856e-03, // K1, K2
|
||||
3.6653586399031184e-03, -3.1960714017365702e-03, // P1, P2
|
||||
0. // K3
|
||||
};
|
||||
Mat _d(1, 5, CV_64F, d);
|
||||
|
||||
// Rotation
|
||||
//double R[9]={1., 0., 0., 0., 1., 0., 0., 0., 1.}; // Identity transform (none)
|
||||
double R[9]={ // Random transform
|
||||
9.6625486010428052e-01, 1.6055789378989216e-02, 2.5708706103628531e-01,
|
||||
-8.0300261706161002e-03, 9.9944797497929860e-01, -3.2237617614807819e-02,
|
||||
-2.5746274294459848e-01, 2.9085338870243265e-02, 9.6585039165403186e-01
|
||||
};
|
||||
Mat _R(3, 3, CV_64F, R);
|
||||
|
||||
// --- Validation --- //
|
||||
initInverseRectificationMap(_K, _d, _R, _K, size_w_h, CV_32FC2, mapxy, noArray());
|
||||
|
||||
// Copy camera matrix
|
||||
double fx, fy, cx, cy, ifx, ify, cxn, cyn;
|
||||
fx = k[0]; fy = k[4]; cx = k[2]; cy = k[5];
|
||||
|
||||
// Copy new camera matrix
|
||||
ifx = k[0]; ify = k[4]; cxn = k[2]; cyn = k[5];
|
||||
|
||||
// Distort Points
|
||||
for( int v = 0; v < size_w_h.height; v++ )
|
||||
{
|
||||
for( int u = 0; u < size_w_h.width; u++ )
|
||||
{
|
||||
// Convert from image to pin-hole coordinates
|
||||
double x = (u - cx)/fx;
|
||||
double y = (v - cy)/fy;
|
||||
|
||||
// Undistort
|
||||
double x2 = x*x, y2 = y*y;
|
||||
double r2 = x2 + y2;
|
||||
double cdist = 1./(1. + (d[0] + (d[1] + d[4]*r2)*r2)*r2); // (1. + (d[5] + (d[6] + d[7]*r2)*r2)*r2) == 1 as d[5-7]=0;
|
||||
double x_ = (x - (d[2]*2.*x*y + d[3]*(r2 + 2.*x2)))*cdist;
|
||||
double y_ = (y - (d[3]*2.*x*y + d[2]*(r2 + 2.*y2)))*cdist;
|
||||
|
||||
// Rectify
|
||||
double X = R[0]*x_ + R[1]*y_ + R[2];
|
||||
double Y = R[3]*x_ + R[4]*y_ + R[5];
|
||||
double Z = R[6]*x_ + R[7]*y_ + R[8];
|
||||
double x__ = X/Z;
|
||||
double y__ = Y/Z;
|
||||
|
||||
// Convert from pin-hole to image coordinates
|
||||
dst.at<Vec2f>(v, u) = Vec2f((float)(x__*ifx + cxn), (float)(y__*ify + cyn));
|
||||
}
|
||||
}
|
||||
|
||||
// Check Result
|
||||
EXPECT_LE(cvtest::norm(dst, mapxy, NORM_INF), 2e-1);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -345,11 +345,16 @@ TEST(usac_P3P, accuracy) {
|
||||
log(1 - pow(inl_ratio, 3 /* sample size */));
|
||||
|
||||
for (auto flag : flags) {
|
||||
std::vector<int> inliers;
|
||||
cv::Mat rvec, tvec, mask, R, P;
|
||||
CV_Assert(cv::solvePnPRansac(obj_pts, img_pts, K1, cv::noArray(), rvec, tvec,
|
||||
false, (int)max_iters, (float)thr, conf, mask, flag));
|
||||
false, (int)max_iters, (float)thr, conf, inliers, flag));
|
||||
cv::Rodrigues(rvec, R);
|
||||
cv::hconcat(K1 * R, K1 * tvec, P);
|
||||
mask.create(pts_size, 1, CV_8U);
|
||||
mask.setTo(Scalar::all(0));
|
||||
for (auto inl : inliers)
|
||||
mask.at<uchar>(inl) = true;
|
||||
checkInliersMask(TestSolver ::PnP, inl_size, thr, img_pts, obj_pts, P, mask);
|
||||
}
|
||||
}
|
||||
@@ -416,19 +421,27 @@ TEST(usac_testUsacParams, accuracy) {
|
||||
// CV_Error(cv::Error::StsError, "Essential matrix estimation failed!");
|
||||
}
|
||||
|
||||
std::vector<int> inliers(pts_size);
|
||||
// P3P
|
||||
inl_size = generatePoints(rng, pts1, pts2, K1, K2, false, pts_size, TestSolver::PnP,
|
||||
getInlierRatio(usac_params.maxIterations, 3, usac_params.confidence), 0.01, gt_inliers);
|
||||
CV_Assert(cv::solvePnPRansac(pts2, pts1, K1, dist_coeff, rvec, tvec, mask, usac_params));
|
||||
CV_Assert(cv::solvePnPRansac(pts2, pts1, K1, dist_coeff, rvec, tvec, inliers, usac_params));
|
||||
cv::Rodrigues(rvec, R); cv::hconcat(K1 * R, K1 * tvec, model);
|
||||
mask.create(pts_size, 1, CV_8U);
|
||||
mask.setTo(Scalar::all(0));
|
||||
for (auto inl : inliers)
|
||||
mask.at<uchar>(inl) = true;
|
||||
checkInliersMask(TestSolver::PnP, inl_size, usac_params.threshold, pts1, pts2, model, mask);
|
||||
|
||||
// P6P
|
||||
inl_size = generatePoints(rng, pts1, pts2, K1, K2, false, pts_size, TestSolver::PnP,
|
||||
getInlierRatio(usac_params.maxIterations, 6, usac_params.confidence), 0.1, gt_inliers);
|
||||
cv::Mat K_est;
|
||||
CV_Assert(cv::solvePnPRansac(pts2, pts1, K_est, dist_coeff, rvec, tvec, mask, usac_params));
|
||||
CV_Assert(cv::solvePnPRansac(pts2, pts1, K_est, dist_coeff, rvec, tvec, inliers, usac_params));
|
||||
cv::Rodrigues(rvec, R); cv::hconcat(K_est * R, K_est * tvec, model);
|
||||
mask.setTo(Scalar::all(0));
|
||||
for (auto inl : inliers)
|
||||
mask.at<uchar>(inl) = true;
|
||||
checkInliersMask(TestSolver::PnP, inl_size, usac_params.threshold, pts1, pts2, model, mask);
|
||||
|
||||
// Affine2D
|
||||
|
||||
@@ -18,8 +18,12 @@ ocv_add_dispatched_file_force_all(test_intrin256 TEST AVX2 AVX512_SKX)
|
||||
ocv_add_dispatched_file_force_all(test_intrin512 TEST AVX512_SKX)
|
||||
|
||||
|
||||
set(PARALLEL_ENABLE_PLUGINS_DEFAULT ON)
|
||||
if(EMSCRIPTEN OR IOS OR WINRT)
|
||||
set(PARALLEL_ENABLE_PLUGINS_DEFAULT OFF)
|
||||
endif()
|
||||
# parallel backends configuration
|
||||
set(PARALLEL_ENABLE_PLUGINS "ON" CACHE BOOL "Allow building parallel plugin support")
|
||||
set(PARALLEL_ENABLE_PLUGINS "${PARALLEL_ENABLE_PLUGINS_DEFAULT}" CACHE BOOL "Allow building parallel plugin support")
|
||||
# TODO building plugins with OpenCV is not supported yet
|
||||
#set(PARALLEL_PLUGIN_LIST "" CACHE STRING "List of parallel backends to be compiled as plugins (tbb, openmp or special value 'all')")
|
||||
#string(REPLACE "," ";" PARALLEL_PLUGIN_LIST "${PARALLEL_PLUGIN_LIST}") # support comma-separated list (,) too
|
||||
|
||||
@@ -538,6 +538,16 @@ _AccTp normInf(const _Tp* a, const _Tp* b, int n)
|
||||
*/
|
||||
CV_EXPORTS_W float cubeRoot(float val);
|
||||
|
||||
/** @overload
|
||||
|
||||
cubeRoot with argument of `double` type calls `std::cbrt(double)`
|
||||
*/
|
||||
static inline
|
||||
double cubeRoot(double val)
|
||||
{
|
||||
return std::cbrt(val);
|
||||
}
|
||||
|
||||
/** @brief Calculates the angle of a 2D vector in degrees.
|
||||
|
||||
The function fastAtan2 calculates the full-range angle of an input 2D vector. The angle is measured
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <opencv2/core/async.hpp>
|
||||
#include <opencv2/core/detail/async_promise.hpp>
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -144,7 +145,30 @@ AsyncArray testAsyncException()
|
||||
return p.getArrayResult();
|
||||
}
|
||||
|
||||
//! @}
|
||||
}} // namespace
|
||||
namespace fs {
|
||||
CV_EXPORTS_W cv::String getCacheDirectoryForDownloads();
|
||||
} // namespace fs
|
||||
|
||||
//! @} // core_utils
|
||||
} // namespace cv::utils
|
||||
|
||||
//! @cond IGNORED
|
||||
|
||||
CV_WRAP static inline
|
||||
int setLogLevel(int level)
|
||||
{
|
||||
// NB: Binding generators doesn't work with enums properly yet, so we define separate overload here
|
||||
return cv::utils::logging::setLogLevel((cv::utils::logging::LogLevel)level);
|
||||
}
|
||||
|
||||
CV_WRAP static inline
|
||||
int getLogLevel()
|
||||
{
|
||||
return cv::utils::logging::getLogLevel();
|
||||
}
|
||||
|
||||
//! @endcond IGNORED
|
||||
|
||||
} // namespaces cv / utils
|
||||
|
||||
#endif // OPENCV_CORE_BINDINGS_UTILS_HPP
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user