Skip to content

Instantly share code, notes, and snippets.

@Curookie
Last active November 9, 2021 14:33
Show Gist options
  • Save Curookie/a2f069522c90ab9947d687778cfa7536 to your computer and use it in GitHub Desktop.
Save Curookie/a2f069522c90ab9947d687778cfa7536 to your computer and use it in GitHub Desktop.
OpenCV
OpenCV
์ปดํ“จํ„ฐ ๋น„์ „ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๊ธฐ ์œ„ํ•œ ์˜คํ”ˆ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ.
[๊ตฌ์„ฑ]
build/include : ํ—ค๋”ํŒŒ์ผ๋“ค์ด ๋“ค์–ด์žˆ๋Š” ๋””๋ ‰ํ„ฐ๋ฆฌ. (.hpp, .h)
build/install/x64/vc14/lib : x64ํ™˜๊ฒฝ Visual Studio 2015์šฉ(vc14) OpenCV Debug/Release ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํŒŒ์ผ๋“ค์ด ๋“ค์–ด์žˆ๋Š” ๋””๋ ‰ํ„ฐ๋ฆฌ (.lib)
build/install/x64/vc14/bin : x64ํ™˜๊ฒฝ Visual Studio 2015์šฉ(vc14) OpenCV Debug/Release ๋™์  ์—ฐ๊ฒฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํŒŒ์ผ๋“ค์ด ๋“ค์–ด์žˆ๋Š” ๋””๋ ‰ํ„ฐ๋ฆฌ (.dll)
ovencv_world_341d.dll -> d๋Š” debug์šฉ ํŒŒ์ผ (์ด ํŒŒ์ผ์€ ํ•˜๋‚˜๋กœ ๋ชจ์•„๋‘” dll ํŒŒ์ผ [์„ค์น˜๋ฒ•]4.์—์„œBUILD_OPENCV_WORLD )
build\etc : haarcascades, lbpcascades XML ํŒŒ์ผ๋“ค์ด ๋“ค์–ด์žˆ๋Š” ๋””๋ ‰ํ„ฐ๋ฆฌ (.xml)
[๋ชจ๋“ˆ]
opencv_core ๋ชจ๋“ˆ : ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ•ต์‹ฌ๊ธฐ๋Šฅ์ด ๋“ค์–ด ์žˆ๋‹ค.
opencv_impproc ๋ชจ๋“ˆ : ์ฃผ์š” ์˜์ƒ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ ํฌํ•จ.
opencv_highgui ๋ชจ๋“ˆ : ์˜์ƒ๊ณผ ๋น„๋””์˜ค ์ฝ๊ธฐ/์“ฐ๊ธฐ ํ•จ์ˆ˜ ์ œ๊ณต. ๋ช‡ ๊ฐ€์ง€ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ์ œ๊ณต.
ํŠน์ • ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ตœ์ƒ์œ„ ํ—ค๋”ํŒŒ์ผ์„ include ํ•ด์•ผํ•œ๋‹ค.
[์„ค์น˜๋ฒ•]
์˜์ƒ(์ปดํ“จํ„ฐ ๋น„์ „) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๊ธฐ์— ๊ณต๊ฐ„์€ ์ ์–ด๋„ 20GB ๋น„์›Œ ๋†“์•„์•ผ ํ•œ๋‹ค.
์ž‘์—…์‹œ๊ฐ„ ์ตœ์†Œ 2์‹œ๊ฐ„
1. opencv.org ์—์„œ ์ตœ์‹ ๋ฒ„์ „ ๋‹ค์šด ํ›„ ์••์ถ•ํ’€๊ธฐ ex) C:\opencv-3.4.1 ์ด๋Ÿฐ์‹์œผ๋กœ
2. ์ตœ์ฒจ๋‹จ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ™œ์šฉํ•˜๊ธฐ์œ„ํ•ด ์ถ”๊ฐ€ ๋ชจ๋“ˆ ์„ค์น˜ github.com/opencv/opencv_contrib์—์„œ
zipํŒŒ์ผ ๋‹ค์šด ํ›„ ์••์ถ•ํ•ด์ œ opencv_contrib-master\modules๋ฅผ contrib๋กœ ํด๋”๋ช… ๋ณ€๊ฒฝ ํ›„ ex) opencv-3.4.1/opencv/sources์— ๋„ฃ๋Š”๋‹ค. (๋‚˜๋จธ์ง„ ํ•„์š”์—†์Œ.)
3. ์˜คํ”ˆ์†Œ์Šค ์†Œํ”„ํŠธ์›จ์–ด ๋„๊ตฌ CMake ๋‹ค์šด. cmake.org .msi ์„ค์น˜ํ˜•์œผ๋กœ ๋ฐ›์•„์„œ Add CMake to the system PATH for all users ์ฒดํฌ (์•ˆํ•ด๋„ ๋œ๋‹ค.)
์„ค์น˜ ์œ„์น˜๋Š” ์ƒ๊ด€์—†๋‹ค. ex) C:\Program Files\CMake\
CMake GUI๋ฅผ ์‚ฌ์šฉํ•ด์„œ opencv ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์†Œ์Šค์™€ ๋ฐ”์ด๋„ˆ๋ฆฌ์žˆ๋Š” ํด๋”์ง€์ •
Where is the source code -> ex) C:\opencv-3.4.1\sources
Where to build the binaries -> ex) C:\opencv-3.4.1\build
4. Tools -> Configure ํ˜„์žฌ ์„ค์น˜๋œ ์ปดํŒŒ์ผ๋Ÿฌ ์„ ํƒ! ex) Visual Studio 14 2015 Win64 Finish๋ฒ„ํŠผ ๋ˆ„๋ฅธ๋‹ค.
๋งŒ์•ฝ ์ž˜๋ชป ๋ˆŒ๋Ÿฌ์„œ ์—๋Ÿฌ ๋ฐœ์ƒ์‹œ File -> Delete Cacheํ•˜๊ณ  ๋‹ค์‹œ 4. ์‹œ๋„ํ•œ๋‹ค.
OPENCV_EXTRA_MODULES_PATH์˜ VALUE์— 2.์—์„œ ๋‹ค์šด๋ฐ›์•˜๋˜ ์ถ”๊ฐ€ ๋ชจ๋“ˆ ์ง€์ • ex) C:/opencv-3.4.1\sources\contrib
Configure ๋ฒ„ํŠผ ํด๋ฆญ
์˜ˆ์ œ๋ฅผ ๋ณด๊ธฐ ์œ„ํ•ด์„  BUILD_OPENCV_EXAMPLE ์ฒดํฌ
์ƒ์—…,๋ฐฐํฌ์šฉ์ด ์•„๋‹Œ๊ฒฝ์šฐ DLL์„ ํ•˜๋‚˜๋กœ ํ†ตํ•ฉํ•ด์ฃผ๋Š” BUILD_OPENCV_WORLD ์ฒดํฌ
CUDA ์„ค์ • ์—„์ฒญ๋‚œ ๋นŒ๋“œ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์œผ๋‚˜ ์‹คํ—˜์šฉ์œผ๋กœ ์“ธ ๊ฒƒ์ด๋ฉด ์ฒดํฌ ๊ด€๋ จ๋œ ๊ฒƒ ์ „๋ถ€ ์–ธ์ฒดํฌ (๋‚œ ๋‹ค ์–ธ์ฒดํฌ)
Python, C ์˜ˆ์ œ ๋ณด๋ ค๋ฉด INSTALL_C_EXAMPLES(๋‚œ ์–ธ์ฒดํฌ), INSTALL_PYTHON_EXAMPLES ์ฒดํฌ
OPENCV์—์„œ OPENGL์„ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๊ฒฝ์šฐ WITH_OPENGL ์ฒดํฌ
C++11๋ฒ„์ „ ์ง€์› Enable_CXX11 ์ฒดํฌ
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ง€์› Build opencv_js ์ฒดํฌ
OPENCV ๋ฌธ์„œ ์ง€์› DOCS ์ฒดํฌ
๋ชจ๋“  ํ•ญ๋ชฉ์ด ๋นจ๊ฐ„์ƒ‰์ด ์‚ฌ๋ผ์งˆ ๋•Œ๊นŒ์ง€ Configure ๋ฒ„ํŠผ ๋ˆ„๋ฅธ๋‹ค. (2-3๋ฒˆ)
5. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ปดํŒŒ์ผ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ํ”„๋กœ์ ํŠธ ํŒŒ์ผ ์ƒ์„ฑ. Generate ๋ฒ„ํŠผ ํด๋ฆญ
6. ํ”„๋กœ์ ํŠธ ํŒŒ์ผ ์‹คํ–‰ ํ›„ Buildํ•˜๊ธฐ. Open Project๋ฒ„ํŠผ ํด๋ฆญ or ex)Visual Studio๋ผ๋ฉด opencv-3.4.1\build\OpenCV.sln์„ ์—ฐ๋‹ค.
๋นŒ๋“œ>์†”๋ฃจ์…˜ ๋นŒ๋“œ Release ์™€ Debug ๊ฐ๊ฐ ๋นŒ๋“œ. ALL BUILD ์ž‘์—…. ๊ทธ ํ›„์— .dll๊ณผ .libํŒŒ์ผ์„ ํŠน์ •ํด๋”์— ๋ชจ์•„๋‘๋Š” INSTALL ๋นŒ๋“œ ์ž‘์—….
INSTALL ํ”„๋กœ์ ํŠธ(CMakeTargets์•„๋ž˜)๋ฅผ ์„ ํƒํ•˜๊ณ  ๋งˆ์šฐ์Šค ์˜ค๋ฅธ์ชฝ Build, Release ์™€ Debug ๊ฐ๊ฐ ๋นŒ๋“œ.
์„ฑ๊ณต ์‹œ install ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ ex) C:\opencv-3.4.1\build\install
install ๋””๋ ‰ํ† ๋ฆฌ์— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋งํฌํ•ด์•ผํ•˜๋Š” OpenCV ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ชจ๋“  ๋ฐ”์ด๋„ˆ๋ฆฌ ํŒŒ์ผ๋“ค, ๋Ÿฐํƒ€์ž„์—์„œ ํ˜ธ์ถœ๊ฐ€๋Šฅํ•˜๋Šฅํ•œ ๋™์ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํŒŒ์ผ๋“ค์ด ๋“ค์–ด์žˆ์Œ.
๋ฆฌ๋ˆ…์Šค ํ™˜๊ฒฝ์ด๋ผ๋ฉด sudo make INSTALL์ด๋‚˜ apt-get
๋งฅOS์—์„  ํ™ˆ๋ธŒ๋ฃจ ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž ์‚ฌ์šฉ. brew install opencv3 -with-contrib ์ž…๋ ฅ
7. ๋
+ VTK ์ถ”๊ฐ€์†Œํ”„ํŠธ์›จ์–ด ์„ค์น˜
cv::viz ๋ชจ๋“ˆ : ์˜์ƒ์œผ๋กœ ๋ถ€ํ„ฐ ์žฅ๋ฉด์˜ 3D ์ •๋ณด๋ฅผ ์žฌ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. ์žฅ๋ฉด ๊ฐ์ฒด์™€ ์นด๋ฉ”๋ผ๋ฅผ ์‹œ๊ฐํ™”ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜ ์ œ๊ณต.
๋‹ค๋ฅธ ์˜คํ”ˆ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ VTK์œ„์—์„œ ๋นŒ๋“œ๋œ ๊ฒƒ์ด๋ฏ€๋กœ OpenCV๋ฅผ ์ปดํŒŒ์ผํ•˜๊ธฐ ์ „์— ์‹œ์Šคํ…œ์— VTK๋ฅผ ์„ค์น˜ํ•ด์•ผํ•œ๋‹ค.
[์„ธํŒ…]
1. ์ƒˆ ์†”๋ฃจ์…˜, ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ, C++ ์ฝ˜์†” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ(vc-15์—์„œ Window ๋ฐ์Šคํฌํ†ฑ ๋งˆ๋ฒ•์‚ฌ ์‹คํ–‰). ์ž์‹ ์˜ ์ปดํ“จํ„ฐ์˜ [ํ”Œ๋ ›ํผ]์— ๋งž๊ฒŒ ์„ค์ • [x84] <-> [x64].
2. ํ”„๋กœ์ ํŠธ ์†์„ฑ์—์„œ [๊ตฌ์„ฑ]-> [๋ชจ๋“ ๊ตฌ์„ฑ]์œผ๋กœ ๋ณ€๊ฒฝ ํ•œ๋ฒˆ์— Debug/Release์„ค์ •์„ ์œ„ํ•ด ๊ทธ๋ฆฌ๊ณ  [C/C++] ์„ ํƒ ํ›„, ์ถ”๊ฐ€ ํฌํ•จ ๋””๋ ‰ํ„ฐ๋ฆฌ build\include ์ถ”๊ฐ€
ex) C:\opencv-3.4.1\build\include
3. [๋ง์ปค]์„ ํƒ ํ›„, [์ถ”๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋””๋ ‰ํ„ฐ๋ฆฌ] ์— OpenCV ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ lib ํŒŒ์ผ ์œ„์น˜ ์ž…๋ ฅ build\install\x64(or x84)\vc??\lib
ex) C:\opencv-3.4.1\build\install\x64\vc14\lib
4. [๊ตฌ์„ฑ์†์„ฑ] -> [๋””๋ฒ„๊น…]์„ ํƒ ํ›„, [ํ™˜๊ฒฝ] ์— OpenCV ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ dll ํŒŒ์ผ ์œ„์น˜ ์ž…๋ ฅ
ex) PATH=C:\opencv-3.4.1\build\install\x64\vc14\bin;%PATH%
5. ํ™•์ธ ๋ˆ„๋ฅด๊ณ  [๊ตฌ์„ฑ]-> [ํ™œ์„ฑ(Debug)] ์„ ํƒ, [๋ง์ปค]-> [์ž…๋ ฅ] -> [์ถ”๊ฐ€์ข…์†์„ฑ] ์— opencv_world๋ฒ„์ „d.lib ์ถ”๊ฐ€ //์ด ์ž‘์—…์€ ".hpp" <.hpp> ๋˜๊ฒŒ ํ•˜๋Š”๊ฒƒ
ex) opencv_world341d.lib;
6. [๊ตฌ์„ฑ]-> [ํ™œ์„ฑ(Release)] ์„ ํƒ, [๋ง์ปค]-> [์ž…๋ ฅ] -> [์ถ”๊ฐ€์ข…์†์„ฑ] ์— opencv_world๋ฒ„์ „.lib ์ถ”๊ฐ€ //์ด ์ž‘์—…์€ ".hpp" <.hpp> ๋˜๊ฒŒ ํ•˜๋Š”๊ฒƒ
ex) opencv_world341.lib;
7. ํ™•์ธ ๋ˆ„๋ฅด๊ณ  ๋ ๋งŒ์•ฝ, cmd์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํ™˜๊ฒฝ๋ณ€์ˆ˜์— ์ถ”๊ฐ€ C:\opencv-3.4.1\build\install\x64\vc15\bin;
[๊ธฐ์ดˆ]
1. ์˜์ƒ์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ๋„์šฐ๊ณ  ์ €์žฅํ•˜๊ธฐ [Playing with Images]
- Depth๋Š” Pixel๋ฅผ ํ‘œํ˜„ํ•˜๋Š” Date Type(์ž๋ฃŒํ˜•)์ด๋ฉฐ ์ •ํ™•ํžˆ๋Š” Channel๋‹น bit์ˆ˜ ๋‹ค.
COLOR(์ปฌ๋Ÿฌ ์˜์ƒ)์ด๋ฉด 3์ฑ„๋„์— ์ฑ„๋„๋‹น 8๋น„ํŠธ์ด๋ฏ€๋กœ Depth๋Š” 3*8=24๋น„ํŠธ์ด๋‹ค.
- cv::Point ๊ตฌ์กฐ์ฒด๋Š” ํŠน์ • ์ ์„ ํ‘œํ˜„ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. (x, y)๋กœ ๊ตฌ์„ฑ
- cv::Scalar ๊ตฌ์กฐ์ฒด๋Š” ์ปฌ๋Ÿฌ ๊ฐ’์„ ์ง€์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. (b, g, r)๋กœ ๊ตฌ์„ฑ BGR์ˆœ์„œ Blue, Green, Red์ˆœ
- cv::Size ๊ตฌ์กฐ์ฒด๋Š” ํŠน์ • ์‚ฌ์ด์ฆˆ๋ฅผ ํ‘œํ˜„ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. (๊ฐ€๋กœ๊ธธ์ดcols, ์„ธ๋กœ๊ธธ์ดrows)๋กœ ๊ตฌ์„ฑ ( <-> ๋‹ค๋ฅธ ๊ฒƒ๊ณผ ์—ญ์ด๋ผ๋Š” ๊ฒƒ ์ƒ๊ฐํ•˜๊ธฐ ๋ณดํ†ต ์„ธ๋กœ,๊ฐ€๋กœ )
- cv::Rect ๊ตฌ์กฐ์ฒด๋Š” ์‚ฌ๊ฐํ˜•์„ ํ‘œํ˜„ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. (x, y, width, height)๋กœ ๊ตฌ์„ฑ
- cv::Range ๊ตฌ์กฐ์ฒด๋Š” ๋ฒ”์œ„๋ฅผ ํ‘œํ˜„ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. (2์ฐจ์› ์ง์„ ), (start, end)๋กœ ๊ตฌ์„ฑ
- ์˜์ƒ์€ ํ–‰๋ ฌ์ด๋‹ค.
- ์ž…๋ ฅ๋ฐฐ์—ด/์ถœ๋ ฅ๋ฐฐ์—ด(1cv::InputArray, cv::OutputArray)๋Š” OpenCV์—์„œ ๋ฐฐ์—ด ๊ฐœ๋…์„ ์ผ๋ฐ˜ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…ํ•œ Proxy Class(ํ”„๋ก์‹œ ํด๋ž˜์Šค)์ด๋‹ค.
์ด๊ฒƒ์˜ ์žฅ์ ์€ ํ•จ์ˆ˜๊ฐ€ ๋ฐ์ดํ„ฐ์˜ ๊ตฌ์กฐ์ฒด๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๋Š”๊ฒƒ์„ ๋ณด์žฅํ•œ๋‹ค.
cv::Mat ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ std::vector(๋‹จ, ํด๋ž˜์Šค๋‚ด๋ถ€or ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•ด์„  ์•ˆ๋จ), cv::Scalar, cv::Vec์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
ex) 2๊ฐœ์˜ ๊ฐ’์„ ๊ฐ–๋Š” ์ด์ง„์˜์ƒ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” cv::threshold() ํ•จ์ˆ˜๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์“ธ ์ˆ˜ ์žˆ๋‹ค.
std::vector<double> src = ~
cv::Mat dst;
cv::threshold(src, dst, 128, 255, cv::THRESH_BINARY);
- cv::Matx ํ…œํ”Œ๋ฆฟ ํด๋ž˜์Šค์™€ ์„œ๋ธŒ ํด๋ž˜์Šค๋Š” ์ž‘์€ ํ–‰๋ ฌ์„ ๋‹ค๋ฃฐ ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
ex) double์˜ 3X3 ํ–‰๋ ฌ๊ณผ 3์›์†Œ ๋ฐฑํ„ฐ์˜ ๊ณฑ
cv::Matx33d matrix(3.0, 2.0, 1.0,
2,0, 1.0, 3.0,
1.0, 2.0, 3.0);
cv::Matx31d vector(5.0, 1.0, 3.0);
cv::Matx31d result = matrix * vector;
- ROI(Region Of Interest) = ๊ด€์‹ฌ ์˜์—ญ : ์˜์ƒํŽธ์ง‘์˜ ๋งˆ์Šคํฌ ๊ธฐ๋Šฅ์ฒ˜๋Ÿผ, ์˜์ƒ์˜ ์ผ๋ถ€์—๋งŒ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•ด์•ผ ํ•  ๋•Œ ์˜์ƒ์—์„œ ๋ถ€๋ถ„์˜์—ญ์„ ์ •์˜ํ•œ ํ›„,
์ผ๋ฐ˜ ์˜์ƒ์œผ๋กœ ๊ฐ„์ฃผํ•ด ๋‹ค๋ฃจ๋Š” ํ›Œ๋ฅญํ•œ ๋งค์ปค๋‹ˆ์ฆ˜์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๋ถ€๋ชจ ์˜์ƒ๊ณผ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ ๋ฒ„ํผ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋ฉฐ, ํ•ต์‹ฌ์€ ROI์ขŒํ‘œ๋ฅผ ์ง€์ •ํ•œ ํ—ค๋”๋ฅผ ๊ฐ€์ง„ cv::Mat ๊ฐ์ฒด์ด๋‹ค.
๋ฐ˜๋“œ์‹œ, copyTo()๋‚˜ clone()๊ฐ™์ด ๊นŠ์€๋ณต์‚ฌ๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋ถ™์—ฌ๋„ฃ์–ด์•ผํ•œ๋‹ค.
๋งˆ์Šคํฌ๋กœ ์“ธ Mat๋Š” ์–‡์€๋ณต์‚ฌ ํ•ด์•ผํ•˜๋ฉฐ(์ด๋ฏธ์ง€ ์ถ”๊ฐ€ ํ•  ๋•Œ๋Š” ๋˜‘๊ฐ™์ด ๊นŠ์€๋ณต์‚ฌ), ๋งˆ์Šคํฌ๋Š” 8๋น„ํŠธ ์˜์ƒ์ด์—ฌ์•ผํ•˜๋ฉฐ, 0์ธ ๋ถ€๋ถ„์„ ํˆฌ๋ช…ํ•˜๊ฒŒ ํ•œ๋‹ค. ๋งˆ์Šคํฌ์ ์šฉํ• ์ถ”๊ฐ€์ด๋ฏธ์ง€.copyTo(ROI, ๋งˆ์Šคํฌ์šฉMat);
1) cv::Rect ์‚ฌ์šฉํ•˜๊ธฐ
ex) cv::Mat imageROI(image, cv::Rect(image.cols - logo.cols, image.rows - logo.rows, logo.cols, logo.rows));
ex) cv::Mat imageROI = image(cv::Rect(image.cols - logo.cols, image.rows - logo.rows, logo.cols, logo.rows));
ex) cv::Rect r(image.cols - logo.cols, image.rows - logo.rows, logo.cols, logo.rows); cv::Mat imageROI= image(r);
2) cv::Range ์‚ฌ์šฉํ•˜๊ธฐ
ex) cv::Mat imageROI = image(cv::Range(image.rows-logo.rows,image.rows), cv::Range(image.cols-logo.cols,image.cols));
3) mask ์‚ฌ์šฉํ•˜๊ธฐ
ex) cv::Mat mask(logo);
logo.copyTo(imageROI, mask);
<์ฝ”๋“œ 1 - ์˜์ƒ์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ๋„์šฐ๊ณ  ์ €์žฅํ•˜๊ธฐ>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
void onMouse(int event, int x, int y, int flags, void* param) {
cv::Mat *im = reinterpret_cast<cv::Mat*>(param);
switch (event)
{
case CV_EVENT_LBUTTONDOWN:
std::cout << "at (" << x << ", " << y << ") value is: " << static_cast<int>(im->at<uchar>(cv::Point(x, y))) << std::endl;
break;
}
}
int main()
{
cv::namedWindow("Original Image");
cv::Mat image = cv::imread("images/puppy.bmp",CV_LOAD_IMAGE_GRAYSCALE);
std::cout << "This image is " << image.rows << "x" << image.cols << std::endl;
std::cout << "This image has " << image.channels() << " channel(s)" << std::endl;
cv::circle(image, cv::Point(155, 100), 65, 0, 3);
cv::putText(image, "This is a dog.", cv::Point(40, 200), cv::FONT_HERSHEY_PLAIN, 2.0, 255, 2);
cv::imshow("Original Image", image);
cv::setMouseCallback("Original Image", onMouse, reinterpret_cast<void*>(&image));
cv::namedWindow("ABC");
cv::flip(image, image, 1);
cv::imshow("ABC", image);
cv::waitKey(0);
cv::imwrite("resultTest01.png", image);
return 0;
}
<์ฝ”๋“œ 2 - cv::Mat ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ฒด ์‚ดํŽด๋ณด๊ธฐ>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
cv::Mat function() {
//์˜์ƒ์ƒ์„ฑ
cv::Mat ima(500, 500, CV_8U,50);
//์ƒ์„ฑ๋œ ์˜์ƒ ๋ฐ˜ํ™˜
return ima;
}
int main()
{
//240ํ–‰๊ณผ 320์—ด๋กœ ๊ตฌ์„ฑ๋œ ์ƒˆ๋กœ์šด ์˜์ƒ ์ƒ์„ฑ
cv::Mat image1(240, 320, CV_8U, 100);
//๋˜๋Š”
//cv::Mat image1(240, 320, CV_8U, cv::Scalar(100));
cv::imshow("Image", image1); //์˜์ƒ๋ณด๊ธฐ
std::cout << "image1's size is " << image1.size<< std::endl;
cv::waitKey(0); //ํ‚ค ์ž…๋ ฅ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ
//์ƒˆ๋กœ์šด ์˜์ƒ์„ ์žฌํ• ๋‹น
image1.create(200, 200, CV_8U);
image1 = 200;
cv::imshow("Image", image1); //์˜์ƒ๋ณด๊ธฐ
cv::waitKey(0); //ํ‚ค ์ž…๋ ฅ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ
//๋นจ๊ฐ„์ƒ‰ ์˜์ƒ ์ƒ์„ฑ
//์ฑ„๋„ ์ˆœ์„œ๋Š” BGR ์ž„
cv::Mat image2(240, 320, CV_8UC3, cv::Scalar(0, 0, 255));
//๋˜๋Š”
//cv::Mat image2(cv::Size(320,240),CV_8UC3);
//image2 = cv::Scalar(0,0,255);
cv::imshow("Image", image2); //์˜์ƒ๋ณด๊ธฐ
cv::waitKey(0); //ํ‚ค ์ž…๋ ฅ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ
//์˜์ƒ์ฝ๊ธฐ
cv::Mat image3 = cv::imread("images/puppy.bmp");
//๋ชจ๋“  ์˜์ƒ์€ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ ๋ธ”๋ก์„ ๊ฐ€๋ฆฌํ‚ด
cv::Mat image4(image3);
image1 = image3;
//์ด๋Ÿฐ ์˜์ƒ์€ ์›์‹œ ์˜์ƒ์˜ ์ƒˆ๋กœ์šด ๋ณต์‚ฌ๋ณธ์ž„
image3.copyTo(image2);
cv::Mat image5 = image3.clone();
//ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ์˜์ƒ์„ ๋ณ€ํ™˜
cv::flip(image3, image3, 1);
//์ฒ˜๋ฆฌ์— ์˜ํ–ฅ์„ ๋ฐ›์€ ์˜์ƒ์ด ์–ด๋–ค์ง€ ํ™•์ธ
cv::imshow("Image 3", image3);
cv::imshow("Image 1", image1);
cv::imshow("Image 2", image2);
cv::imshow("Image 4", image4);
cv::imshow("Image 5", image5);
cv::waitKey(0);
//function ํ•จ์ˆ˜๋กœ๋ถ€ํ„ฐ ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ์˜์ƒ ์–ป๊ธฐ
cv::Mat gray = function();
cv::imshow("Image", gray); //์˜์ƒ๋ณด๊ธฐ
cv::waitKey(0); //ํ‚ค ์ž…๋ ฅ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ
//์˜์ƒ์„ ๊ทธ๋ ˆ์ด์Šค์ผ€์ผ๋กœ ์ฝ๊ธฐ
image1 = cv::imread("images/puppy.bmp", CV_LOAD_IMAGE_GRAYSCALE);
image1.convertTo(image2, CV_32F, 1/255.0, 0.0);
cv::imshow("Image", image2); //์˜์ƒ๋ณด๊ธฐ
cv::waitKey(0); //ํ‚ค ์ž…๋ ฅ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ
//ํ–‰๋ ฌ Matx ํด๋ž˜์Šค ์˜ˆ์ œ
cv::Matx33d matrix(3.0, 2.0, 1.0,
2.0, 1.0, 3.0,
1.0, 2.0, 3.0);
cv::Matx31d vector(5.0, 1.0, 3.0);
cv::Matx31d result = matrix * vector;
std::cout << result;
cv::waitKey(0);
return 0;
}
<์ฝ”๋“œ 3 - ๊ด€์‹ฌ ์˜์—ญ ์ •์˜>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
int main()
{
cv::namedWindow("Image");
cv::Mat image = cv::imread("images/puppy.bmp");
cv::Mat logo = cv::imread("images/smalllogo.png");
//์˜์ƒ์˜ ์˜ค๋ฅธ์ชฝ ํ•˜๋‹จ์—์„œ ์˜์ƒ ROI ์ •์˜, Rect(x,y,width,height)
cv::Mat imageROI(image, cv::Rect(image.cols - logo.cols, image.rows - logo.rows, logo.cols, logo.rows));
//๋กœ๊ณ ์‚ฝ์ž…
logo.copyTo(imageROI);
cv::imshow("Image",image);
cv::waitKey();
//์ƒˆ๋กœ์šด ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ์„ ์œ„ํ•ด ๋‹ค์‹œ๋กœ๋“œ
image = cv::imread("images/puppy.bmp");
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•์œผ๋กœ ์™ผ์ชฝ์•„๋ž˜์— ์˜์ƒ ROI ์ •์˜
imageROI = image(cv::Range(image.rows - logo.rows, image.rows), cv::Range(0, logo.cols));
//์ด๋ฒˆ์—” ๋งˆ์Šคํฌ๋กœ ์“ธ ์ด๋ฏธ์ง€ ์–‡์€๋ณต์‚ฌ, ๋งˆ์Šคํฌ๋Š” 8๋น„ํŠธ ์˜์ƒ์ด์—ฌ์•ผํ•˜๋ฉฐ, 0์ธ ๋ถ€๋ถ„์„ ํˆฌ๋ช…ํ•˜๊ฒŒ ํ•œ๋‹ค.
cv::Mat mask(logo);
logo.copyTo(imageROI, mask);
cv::imshow("Image2", image);
cv::waitKey();
}
2. ํ™”์†Œ ๋‹ค๋ฃจ๊ธฐ [Manipulating the Pixels]
- ํ™”์†Œ(Pixel)๋Š” ํ–‰๋ ฌ์˜ ๊ฐ ์›์†Œ.
- ์›์†Œ๊ฐ€ ๋‹จ์ผ ์ˆ˜์น˜ ๊ฐ’์ด๊ฑฐ๋‚˜ ๋‹ค์ค‘ ์ฑ„๋„ ์˜์ƒ์ธ ๊ฒฝ์šฐ, ๊ฐ’์ด ๋ฐฑํ„ฐ์ผ ์ˆ˜ ์žˆ๋‹ค.
- salt-and-pepper noise๋Š” ํฐ์ƒ‰(0), ๊ฒ€์€์ƒ‰(255)์„ ๋ฒˆ๊ฐˆ์•„ ๊ฐ€๋ฉฐ ๋„ฃ๋Š” ๋…ธ์ด์ฆˆ๋ฅผ ๋œปํ•œ๋‹ค.
- impulse noise๋Š” ํฐ์ƒ‰(0)์ด๋‚˜ ๊ฒ€์€์ƒ‰(255) ํ•œ๊ฐ€์ง€๋งŒ ๋„ฃ๋Š” ๋…ธ์ด์ฆˆ๋ฅผ ๋งํ•œ๋‹ค.
- cv::Vec!? (= cv::Vec<T,N>) ๊ตฌ์กฐ์ฒด๋Š” ํŠน์ •๊ฐœ์ˆ˜์˜ ์›์†Œ์˜ ์ง‘ํ•ฉ, ๋ฐฑํ„ฐํ˜•์„ ํ‘œํ˜„ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. (!์— ์›์†Œ์˜ ๊ฐœ์ˆ˜ 2,3,4 ๋“ฑ) (?์— b = byte, l = long, f = float, d = double, s = short ๋“ฑ)
- CV_Assert(expr) ๋งคํฌ๋กœ : expr ์กฐ๊ฑด์‹์ด ๊ฑฐ์ง“์ด๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
ex) CV_Assert(image.type() == CV_8UC1); // ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ์ด ์•„๋‹๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ
- ํ–‰ ๋งˆ๋‹ค ์›์†Œ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ์ค‘๋ณต๋˜๋Š” ์›์†Œ๋Š” ํฌํ•จ๋˜์ง€ ์•Š๊ธฐ์—(?)
- ์ปฌ๋Ÿฌ ๊ฐ์†Œ ์ž‘์—… : CV_8U3C์˜ ์ปฌ๋Ÿฌ์˜ ์ด ๊ฐœ์ˆ˜๋Š” 256*256*256 = ์•ฝ 1,600๋งŒ ์ปฌ๋Ÿฌ ์ด์ƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ ๋ถ„์„๋ณต์žก๋„๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด ์ปฌ๋Ÿฌ ๊ฐ์†Œ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋“ค์ด ์กด์žฌํ•œ๋‹ค.
1) ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๊ธฐ๋ณธ ์ปฌ๋Ÿฌ ๊ฐ์†Œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ : N์ด ๊ฐ์†Œ์ธ์ž์ด๋ฉด ์˜์ƒ์˜ ๊ฐ ํ™”์†Œ์™€ ํ•ด๋‹น ํ™”์†Œ์˜ ๊ฐ ์ฑ„๋„์„ N์œผ๋กœ ๋‚˜๋ˆˆ๋‹ค.(์ •์ˆ˜๋กœ ๋‚˜๋ˆ„๊ธฐ์— ๋‚˜๋จธ์ง€๋ฅผ ์žƒ๋Š”๋‹ค.) ๊ทธ๋Ÿฐ๋‹ค์Œ N์„ ๊ณฑํ•˜๊ณ (N์˜ ๋ฐฐ์ˆ˜๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์ž‘์—…) N/2๋ฅผ ๋”ํ•ด ์ค‘๊ฐ„๊ฐ’์œผ๋กœ ๋ณด์ •ํ•œ๋‹ค.
๊ฒฐ๊ตญ 256/N * 256/N * 256/N ์ธ ์ปฌ๋Ÿฌ ๊ฐœ์ˆ˜๋กœ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.
์‹ : data/N*N + N/2
2) ๋น„์Šทํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ์•Œ๊ณ ๋ฆฌ์ฆ˜1 : ๋‚˜๋จธ์ง€ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜.
์‹ : data - data%N + N/2
3) ๋น„์Šทํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ํšจ์œจ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜2 : ๋น„ํŠธ๋ณ„ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜. pow(2,n)์œผ๋กœ ์ œํ•œํ–ˆ์„ ๋•Œ ํ™”์†Œ ๊ฐ’์˜ ์ฒซ๋ฒˆ ์งธ n๋น„ํŠธ๋ฅผ ๋งˆ์Šคํ‚นํ•˜๋ฉด div์˜ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋‚ฎ์€ ๋ฐฐ์ˆ˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ๋‹ค๋ฅธ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋ณด๋‹ค ํšจ์œจ์ ์ด๋‹ค.
์‹ : mask = 0xFF<<(logN/log2), data &= mask and data |= div>>1
- ์˜์ƒ์ฒ˜๋ฆฌ์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ด์›ƒํ•˜๋Š” ํ™”์†Œ ๊ฐ’์— ๊ธฐ๋ฐ˜์„ ๋‘๊ณ  ๊ฐ ํ™”์†Œ ์œ„์น˜์˜ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š” ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. = ์ด์›ƒ ์ ‘๊ทผ์œผ๋กœ ์˜์ƒ ์กฐํšŒ
- ์˜์ƒ์„ ์„ ๋ช…ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋Š” ๋ผํ”Œ๋ผ์‹œ์•ˆ ์—ฐ์‚ฐ์ž(6๊ฐ•)์— ๊ธฐ๋ฐ˜์„ ๋‘”๋‹ค. ์˜์ƒ์— ๋ผํ”Œ๋ผ์‹œ์•ˆ์„ ๋นผ๋ฉด ์˜์ƒ ์—์ง€๊ฐ€ ๋‘๋“œ๋Ÿฌ์ง€๊ฒŒ ๋ผ ๊ฒฐ๊ตญ ์„ ๋ช…ํ•œ ์˜์ƒ์„ ์–ป๊ฒŒ๋œ๋‹ค.
- ์„ ๋ช…ํ™” ์ฒ˜๋ฆฌ, ์ƒคํ”„๋‹ : sharpened_pixel = 5*current - left - right - up - down; 3๊ฐœ์˜ ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ํ˜„์žฌ ํ–‰, ์œ„ ํ–‰, ์•„๋ž˜ ํ–‰
ํ™”์†Œ ๊ณ„์‚ฐ ์‹œ ์ด์›ƒ์— ์ ‘๊ทผํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ฒซ ํ–‰,์—ด๊ณผ ๋งˆ์ง€๋ง‰ ํ–‰,์—ด์˜ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
1) ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•: ํฌ์ธํ„ฐ๋ฅผ ์ƒ์„ฑํ•ด์„œ ๊ณ„์‚ฐํ•˜๊ธฐ. ๊ฒ€์€ ํ…Œ๋‘๋ฆฌ๊ฐ€ ์ƒ๊ธด๋‹ค. ๊ฒ€์€ ํ…Œ๋‘๋ฆฌ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜๋“ค๋„ ์žˆ๋‹ค.
2) ์ปค๋„ ํ–‰๋ ฌ, ์ปค๋„์€ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ๊ณ„์‚ฐ์— ๊ด€๋ จ๋œ ํ™”์†Œ๋ฅผ ์กฐํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ธฐ์ˆ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
[ 0 -1 0 ]
[-1 5 -1 ]
[ 0 -1 0 ]
๋ณ„ ๋‹ค๋ฅธ ์–ธ๊ธ‰์ด ์—†๋Š”๊ฒฝ์šฐ ํ˜„์žฌ์˜ ํ™”์†Œ๋Š” ์ปค๋„์˜ ์ค‘์‹ฌ, ์ปค๋„์˜ ํฌ๊ธฐ๋Š” ์ด์›ƒ์˜ ํฌ๊ธฐ์ด๋ฉฐ, ์ปค๋„์€ ์˜์ƒ์— ์ ์šฉํ•˜๋Š” ํ•„ํ„ฐ๋ฅผ ์ •์˜ํ•œ๋‹ค.(๊ณฑํ•œ๋‹ค)
cv::filter2D ์™€ ์ปค๋„ํ–‰๋ ฌ์„ ์‚ฌ์šฉํ•ด์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒ€์€ ํ…Œ๋‘๋ฆฌ๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š๋Š”๋‹ค. ํฐ ์ปค๋„์ผ ๊ฒฝ์šฐ ๋”์šฑ ์œ ๋ฆฌํ•˜๋‹ค.
3) Iterator๋ฐ˜๋ณต์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ• : ๋ฐ˜๋ณต์ž๋ฅผ ํฌ์ธํ„ฐ์„ ์–ธ์ฒ˜๋Ÿผํ•ด์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค. ๊ฒ€์€ ํ…Œ๋‘๋ฆฌ๊ฐ€ ์ƒ๊ธฐ๋ฉฐ ํ‘๋ฐฑ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.
ex)
//๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ์ด๋ฏธ์ง€์—ฌ์•ผํ•จ.
CV_Assert(image.type() == CV_8UC1);
//๋ฐ˜๋ณต์ž๋“ค์„ 1ํ–‰์œผ๋กœ ์ดˆ๊ธฐํ™”
cv::Mat_<uchar>::const_iterator it = image.begin<uchar>() + image.cols;
cv::MatConstIterator_<uchar> itend = image.end<uchar>() - image.cols;
cv::Mat_<uchar>::const_iterator itup = image.begin<uchar>();
cv::MatConstIterator_<uchar> itdown = image.begin<uchar>() + 2*image.cols;
//์žฌํ• ๋‹น ํ•„์š”์„ฑ์„ ์œ„ํ•ด
result.create(image.size(), image.type());
//output ๋ฐ˜๋ณต์ž ์„ค์ •
cv::Mat_<uchar>::iterator itout = result.begin<uchar>() + result.cols;
for (; it != itend; ++it, ++itout, ++itup, ++itdown) {
*itout = cv::saturate_cast<uchar>(*it * 5 - *(it - 1) - *(it + 1) - *itup - *itdown);
}
//์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์€ ์˜์—ญ 0์œผ๋กœ
result.row(0).setTo(cv::Scalar(0));
result.row(result.rows - 1).setTo(cv::Scalar(0));
result.col(0).setTo(cv::Scalar(0));
result.col(result.cols - 1).setTo(cv::Scalar(0));
- ์˜์ƒ์˜ ์‚ฐ์ˆ  ์—ฐ์‚ฐ : ์—ฐ์‚ฐ์ž๋กœ๋„ ๊ฐ€๋Šฅํ•˜๊ณ  ๊ฐ์ข… ์‚ฐ์ˆ  ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŠน์ • ์˜์ƒ์˜ ํ™”์†Œ๊ฐ’์„ ์‚ฐ์ˆ  ํ•  ์ˆ˜ ์žˆ๋‹ค.
๋ชจ๋“  ์‚ฐ์ˆ  ์—ฐ์‚ฐ์ž๋Š” ๊ฒฐ๊ณผ๊ฐ€ ์ž…๋ ฅ ํƒ€์ž…์˜ ๋ฒ”์œ„ ์•ˆ์— ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ํ•ญ์ƒ saturate_cast() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
ex) result = 0.7* image1 + 0.9*image2; //๊ฐ€์ค‘์น˜๋ฅผ ๋‘” ADD๋ฅผ ์—ฐ์‚ฐ์ž๋กœ ์—ฐ์‚ฐํ•œ ๊ฒƒ
ex) cv::addWeighted(image1, 0.7, image2, 0.9, 0., result); //์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ
์—ฐ์‚ฐ์ž์˜ ์ข…๋ฅ˜ add, subtract, absdiff, multiply, divide, bitwise_and, bitwise_or, bitwise_xor, bitwise_not, min, max, sqrt, pow, abs, cuberoot, exp, log ๋“ฑ๋“ฑ.
๊ทธ ์™ธ ์ˆ˜ํ•™ํ•จ์ˆ˜ ์—ญํ–‰๋ ฌ m1.inv(), ์ „์น˜ mt1.t(), ํ–‰๋ ฌ์‹ m1.determinant(), ํ–‰๋ ฌ์‹ v1.norm(), ์™ธ์  v1.cross(v2), ๋‚ด์  v1.dot(v2)
์นผ๋ผ๊ฐ์†Œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‚ฐ์ˆ  ์—ฐ์‚ฐ์ž๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•œ ์˜ˆ์‹œ) image = (image & cv::Scalar(mask, mask, mask)) + cv::Scalar(div / 2, div / 2, div / 2);
- ์˜์ƒ ์ฑ„๋„ ๋ถ„๋ฆฌ/๊ฒฐํ•ฉ : ๊ฐ ์ฑ„๋„์„ ๋”ฐ๋กœ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. cv::split(๋ถ„๋ฆฌํ• , ๋ถ„๋ฆฌ๋œ) ๊ณผ cv::merge(ํ•ฉ์น ,ํ•ฉ์ณ์ง„)๋กœ ๊ฐ€๋Šฅํ•˜๋‹ค.
ex) // 3๊ฐœ์˜ Mat๋กœ ์ด๋ค„์ง„ Vector ์„ ์–ธ
std::vector<cv::Mat> planes;
// 3์ฑ„๋„ ์ด๋ฏธ์ง€์˜ ์ฑ„๋„์„ ๋ชจ๋‘ ๋‚˜๋ˆ  3๊ฐœ์˜ ์ด๋ฏธ์ง€๋กœ splitํ•จ์ˆ˜
cv::split(image1, planes);
// ๋ธ”๋ฃจ์ฑ„๋„์— ADDํ•˜๊ธฐ
planes[0] += image2;
// ๋‹ค์‹œ 3์ฑ„๋„ ํ•ฉ์ณ์„œ ํ•˜๋‚˜์˜ 3์ฑ„๋„ ์ด๋ฏธ์ง€๋กœ
cv::merge(planes, result);
- ์˜์ƒ ์žฌ๋งคํ•‘ : ์˜์ƒ์˜ ํ™”์†Œ๋ฅผ ์˜ฎ๊ฒจ ์˜์ƒ์˜ ๋ชจ์Šต์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ, ํ™”์†Œ ๊ฐ’์„ ๋ฐ”๊พธ์ง€ ์•Š๋Š” ๋Œ€์‹  ํ™”์†Œ์˜ ์œ„์น˜๋ฅผ ์žฌ๋งคํ•‘ํ•œ๋‹ค. ํŠน์ˆ˜ํ•œ ํšจ๊ณผ๋‚˜ ์˜์ƒ ์™œ๊ณก์„ ๋ณด์ •ํ•  ๋•Œ ๋งค์šฐ ์œ ์šฉํ•˜๋‹ค.
remapํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์žฌ๋งคํ•‘ ๋งต์„ ๋จผ์ € ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋‹ค์Œ ์ž…๋ ฅ์˜์ƒ์— ๋งต์„ ์ ์šฉํ•œ๋‹ค.
์—ญ๋ฐฉํ–ฅ๋งคํ•‘์ด๋ผ๊ณ  ํ•˜๋Š”๋ฐ ๋ณ€ํ™˜์ด ์ƒˆ๋กœ์šด ์˜์ƒ์˜ ํ™”์†Œ๋ฅผ ์›๋ณธ ์˜์ƒ์— ์žฌ๋งคํ•‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ธฐ์ˆ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
์‹ค์ œํ™”์†Œ ์‚ฌ์ด์— ์žˆ๋Š” ๊ฐ€์ƒํ™”์†Œ์˜ ๊ฐ’์„ ๋ณด๊ฐ„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด 5๋ฒˆ์งธ ์ธ์ž ๋ณด๊ฐ„๋ฐฉ๋ฒ•์— ์˜ํ•ด ์ •ํ•ด์ง„๋‹ค. (*ํ™”์†Œ ๋ณด๊ฐ„์€ 6์—์„œ ๋” ์ž์„ธํ•˜๊ฒŒ)
<์ฝ”๋“œ 1 - ํ™”์†Œ ๊ฐ’์— ์ ‘๊ทผํ•˜๊ธฐ/ ๋…ธ์ด์ฆˆ ๋งŒ๋“ค๊ธฐ>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <random>
void salt(cv::Mat image, int n) {
//C++11 ๋‚œ์ˆ˜์ƒ์„ฑ๊ธฐ
std::default_random_engine generator;
std::uniform_int_distribution<int> randomRow(0, image.rows - 1);
std::uniform_int_distribution<int> randomCol(0, image.cols - 1);
int i, j;
for (int k = 0; k < n; k++)
{
//๋ฌด์ž‘์œ„ ์˜์ƒ ์ขŒํ‘œ
i = randomCol(generator);
j = randomRow(generator);
//๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ์˜์ƒ CV_8U ๋ง๊ณ  CV_8UC1์ด๋ผ๊ณ  ํ‘œํ˜„๊ฐ€๋Šฅ
if (image.type() == CV_8UC1) {
image.at<uchar>(j, i) = 255;
}
else if (image.type() == CV_8UC3) {
//3์ฑ„๋„ ์ด๊ธฐ์— Vec3b ๋ฅผ ์‚ฌ์šฉ. b๋Š” byte ucharํ˜•์„ ์˜๋ฏธ
image.at<cv::Vec3b>(j, i)[0] = 255;
image.at<cv::Vec3b>(j, i)[1] = 255;
image.at<cv::Vec3b>(j, i)[2] = 255;
// ์ด๋ ‡๊ฒŒ ์“ธ์ˆ˜๋„ ์žˆ๋‹ค.
// image.at<cv::Vec3b>(j, i) = cv::Vec3b(255, 255, 255);
}
}
}
void salt2(cv::Mat image, int n)
{
CV_Assert(image.type() == CV_8UC1);
//C++11 ๋‚œ์ˆ˜์ƒ์„ฑ๊ธฐ
std::default_random_engine generator;
std::uniform_int_distribution<int> randomRow(0, image.rows - 1);
std::uniform_int_distribution<int> randomCol(0, image.cols - 1);
//cv::Mat_ ํ…œํ”Œ๋ฆฟํด๋ž˜์Šค ์‚ฌ์šฉ
//์„œ๋ธŒ ํด๋ž˜์Šค๋กœ ์ƒ์„ฑ
cv::Mat_<uchar> img1(image);
//์ฐธ์กฐํ˜•์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ•
cv::Mat_<uchar>& img2= reinterpret_cast<cv::Mat_<uchar>&>(image);
int i, j;
for (int k = 0; k < n; k++)
{
i = randomCol(generator);
j = randomRow(generator);
img1(j, i) = 255;
}
}
int main()
{
cv::namedWindow("Image");
cv::Mat image = cv::imread("../images/boldt.jpg",1);
salt(image, 3000);
cv::imshow("Image", image);
cv::waitKey();
image = cv::imread("../images/boldt.jpg", 0);
salt2(image, 500);
cv::imshow("Image", image);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 2 - ํฌ์ธํ„ฐ๋กœ ์˜์ƒ ์กฐํšŒ/ ์นผ๋ผ ๊ฐ์†Œ ์•Œ๊ณ ๋ฆฌ์ฆ˜>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
//๊ธฐ๋ณธ
void colorReduce(cv::Mat image, int div = 64)
{
int nl = image.rows; // ํ–‰์˜ ๊ฐœ์ˆ˜
int nc = image.cols * image.channels(); // ๊ฐ ํ–‰์˜ ์›์†Œ(channel) ์ด ๊ฐœ์ˆ˜
for (int j = 0; j < nl; j++)
{
uchar* data = image.ptr<uchar>(j);
for (int i = 0; i < nc; i++)
{
data[i] = data[i] / div * div + div / 2;
}
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•1
void colorReduce1(cv::Mat image, int div = 64)
{
int nl = image.rows;
int nc = image.cols * image.channels();
uchar div2 = div >> 1; // div2 = div/2
for (int j = 0; j<nl; j++) {
uchar* data = image.ptr<uchar>(j);
for (int i = 0; i<nc; i++)
{
*data++ = *data / div * div + div2; // ํฌ์ธํ„ฐ์‚ฐ์ˆ ์„ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด๋ ‡๊ฒŒ๋„ ์‚ฌ์šฉ๊ฐ€๋Šฅ
}
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•2
void colorReduce2(cv::Mat image, int div = 64)
{
int nl = image.rows;
int nc = image.cols * image.channels();
uchar div2 = div >> 1; // div2 = div/2
for (int j = 0; j<nl; j++) {
uchar* data = image.ptr<uchar>(j);
for (int i = 0; i<nc; i++)
{
int v = *data;
*data++ = v - v % div + div2; // ๋‚˜๋จธ์ง€์—ฐ์‚ฐ์ž+ํฌ์ธํ„ฐ์‚ฐ์ˆ ์„ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด๋ ‡๊ฒŒ๋„ ์‚ฌ์šฉ๊ฐ€๋Šฅ
}
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•3
void colorReduce3(cv::Mat image, int div = 64)
{
int nl = image.rows;
int nc = image.cols * image.channels();
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0) + 0.5); // + 0.5๋Š” ๋ฐ˜์˜ฌ๋ฆผ logA/logB = log_B A์™€๊ฐ™์Œ log_2 2^6 = 6.0
//ํ™”์†Œ ๊ฐ’์„ ๋ฐ˜์˜ฌ๋ฆผํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋งˆ์Šคํฌ
uchar mask = 0xFF << n; // e.g. for div=16, mask= 0xF0
uchar div2 = 1 << (n - 1); // div2 = div/2 (๋‹จ div๋Š” 2^n)
for (int j = 0; j<nl; j++) {
uchar* data = image.ptr<uchar>(j);
for (int i = 0; i<nc; i++)
{
*data &= mask; // ๋งˆ์Šคํ‚นํ•˜๋Š” and๋น„ํŠธ์—ฐ์‚ฐ
*data++ |= div2; // or๋น„ํŠธ์—ฐ์‚ฐ์œผ๋กœ div/2 ๋”ํ•˜๊ธฐ
//*data++ += div2; // div/2 ๋”ํ•˜๊ธฐ
}
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•3-2 ์ €์ˆ˜์ค€ ํฌ์ธํ„ฐ ์‚ฐ์ˆ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šฐ๋ฏ€๋กœ ์ถ”์ฒœํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์•„๋‹˜
void colorReduce4(cv::Mat image, int div = 64)
{
int nl = image.rows;
int nc = image.cols * image.channels();
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0) + 0.5); // + 0.5๋Š” ๋ฐ˜์˜ฌ๋ฆผ logA/logB = log_B A์™€๊ฐ™์Œ log_2 2^6 = 6.0
int step = image.step; //์œ ํšจ๋„ˆ๋น„๋ฅผ ๋ฐ”์ดํŠธ๋‹จ์œ„(=uchar)๋กœ ์ €์žฅ
//ํ™”์†Œ ๊ฐ’์„ ๋ฐ˜์˜ฌ๋ฆผํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋งˆ์Šคํฌ
uchar mask = 0xFF << n; // e.g. for div=16, mask= 0xF0
uchar div2 = 1 << (n - 1); // div2 = div/2 (๋‹จ div๋Š” 2^n)
uchar* data = image.data; // ๋ฐ์ดํ„ฐ๋ธ”๋ก์˜ ์ฒซ ์ง€์  ๊ฐ€์ ธ์˜ค๊ธฐ
for (int j = 0; j<nl; j++) {
for (int i = 0; i<nc; i++)
{
*(data+i) &= mask; // ๋งˆ์Šคํ‚นํ•˜๋Š” and๋น„ํŠธ์—ฐ์‚ฐ
*(data+i) += div2; // div/2 ๋”ํ•˜๊ธฐ
//*(data+i) |= div2; // or๋น„ํŠธ์—ฐ์‚ฐ์œผ๋กœ div/2 ๋”ํ•˜๊ธฐ
//std::cout<<*(data+i)<<std::endl;
}
data += step; // ๋‹ค์Œ ํ–‰ ์ฃผ์†Œ๊ฐ€์ ธ์˜ค๊ธฐ
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•3-3 ํ–‰์˜ ์›์†Œ๊ฐœ์ˆ˜๋ฅผ ์žฌ๊ณ„์‚ฐํ•ด์„œ ํ•˜๋Š”๋ฐฉ๋ฒ• ๋А๋ฆฌ๋‹ค. ์ด๋ ‡๊ฒŒํ•ด์„  ์•ˆ๋˜๋Š” ์˜ˆ
void colorReduce5(cv::Mat image, int div = 64)
{
int nl = image.rows;
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0) + 0.5); // + 0.5๋Š” ๋ฐ˜์˜ฌ๋ฆผ logA/logB = log_B A์™€๊ฐ™์Œ log_2 2^6 = 6.0
//ํ™”์†Œ ๊ฐ’์„ ๋ฐ˜์˜ฌ๋ฆผํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋งˆ์Šคํฌ
uchar mask = 0xFF << n; // e.g. for div=16, mask= 0xF0
uchar div2 = 1 << (n - 1); // div2 = div/2 (๋‹จ div๋Š” 2^n)
for (int j = 0; j<nl; j++) {
uchar* data = image.ptr<uchar>(j);
//ํ–‰์˜ ์›์†Œ๊ฐœ์ˆ˜๋ฅผ ์žฌ๊ฐœ์‚ฐ ๋น„ํšจ์œจ์ ์ธ ์ฝ”๋“œ
for (int i = 0; i<image.cols * image.channels(); i++)
{
*data &= mask; // ๋งˆ์Šคํ‚นํ•˜๋Š” and๋น„ํŠธ์—ฐ์‚ฐ
*data++ += div2; // div/2 ๋”ํ•˜๊ธฐ
}
}
}
//์ธํ’‹,์•„์›ƒํ’‹ ๋ชจ๋ธ
void colorReduceIO(const cv::Mat &image, cv::Mat &result, int div = 64)
{
int nl = image.rows;
int nc = image.cols;
int nchannels = image.channels();
//๋งŒ์•ฝ ์•„์›ƒํ’‹ ๋ชจ๋ธ์˜ ํฌ๊ธฐ์™€ ํƒ€์ž…์ด ์ธํ’‹ ๋ชจ๋ธ๊ณผ ๋‹ค๋ฅผ ๊ฒฝ์šฐ ์ˆ˜์ •
result.create(image.rows, image.cols, image.type());
for (int j = 0; j<nl; j++) {
//์ธํ’‹, ์•„์›ƒํ’‹ ๋ชจ๋ธ์˜ ํ–‰ ์ฃผ์†Œ ๊ฐ€์ ธ์˜ค๊ธฐ
const uchar* data_in = image.ptr<uchar>(j);
uchar* data_out = result.ptr<uchar>(j);
for (int i = 0; i<nc*nchannels; i++) {
data_out[i] = data_in[i] / div * div + div / 2;
}
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•3-4 ๋งŒ์•ฝ ์ถ”๊ฐ€ํ™”์†Œ๊ฐ€ ์—†๋Š”๊ฒฝ์šฐ ์ง๋ ฌ๋กœ ๊ณ„์‚ฐ ๋ฐ˜๋ณต๋ฌธ j๋ฅผ ๋ฌดํšจํ™” ํ•จ 2์ฐจ-> 1์ฐจ ๋” ํšจ์œจ์„ฑ์„ ๋†’์ž„
void colorReduce6(cv::Mat image, int div = 64)
{
int nl = image.rows;
int nc = image.cols * image.channels();
if (image.isContinuous()) {
nc = nc*nl;
nl = 1;
}
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0) + 0.5);
uchar mask = 0xFF << n;
uchar div2 = div >> 1;
for (int j = 0; j < nl; j++)
{
uchar *data = image.ptr<uchar>(j);
for (int i = 0; i < nc; i++) {
*data &= mask;
*data++ += div2;
}
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•3-5 reshapeํ•จ์ˆ˜๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ณต์‚ฌ๋‚˜ ๋‹ค์‹œํ• ๋‹น์—†์ด ์ฐจ์› ์ˆ˜๋ฅผ ๋ณ€๊ฒฝ
void colorReduce7(cv::Mat image, int div = 64)
{
if (image.isContinuous()) {
image.reshape(1, 1);
}
int nl = image.rows;
int nc = image.cols * image.channels();
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0) + 0.5);
uchar mask = 0xFF << n;
uchar div2 = div >> 1;
for (int j = 0; j < nl; j++)
{
uchar *data = image.ptr<uchar>(j);
for (int i = 0; i < nc; i++) {
*data &= mask;
*data++ += div2;
}
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•4 ์•Œ๊ณ ๋ฆฌ์ฆ˜ํ˜•ํƒœ๋Š” ๊ธฐ๋ณธ๊ณผ ๊ฐ™์œผ๋‚˜ Iterator ๋ฐ˜๋ณต์ž๋ฅผ ์‚ฌ์šฉํ•ด ์กฐํšŒ
void colorReduce8(cv::Mat image, int div = 64)
{
cv::MatIterator_<cv::Vec3b> it = image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>(); //์œ„ ์•„๋ž˜ ์„ ์–ธ ๊ฐ™์€ ์˜๋ฏธ
uchar div2 = div >> 1;
for (; it != itend; it++)
{
(*it)[0] = (*it)[0] / div * div + div2;
(*it)[1] = (*it)[1] / div * div + div2;
(*it)[2] = (*it)[2] / div * div + div2;
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•4-2 ๋ฐ˜๋ณต์ž ํ•œ๋ฒˆ์— ํ‘œํ˜„
void colorReduce9(cv::Mat image, int div = 64)
{
cv::MatIterator_<cv::Vec3b> it = image.begin<cv::Vec3b>();
cv::MatIterator_<cv::Vec3b> itend = image.end<cv::Vec3b>();
const cv::Vec3b div2(div/2,div/2,div/2);
for (; it != itend; it++)
{
*it = *it / div * div + div2;
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•4-3 ๋ฐ˜๋ณต์ž ๋ฐ”์ด๋„ˆ๋ฆฌ ๋งˆ์Šคํฌ
void colorReduce10(cv::Mat image, int div = 64)
{
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0) + 0.5);
uchar mask = 0xFF << n;
uchar div2 = div >> 1;
cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>();
for (; it != itend; it++)
{
(*it)[0] &= mask;
(*it)[0] += div2;
(*it)[1] &= mask;
(*it)[1] += div2;
(*it)[2] &= mask;
(*it)[2] += div2;
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•4-4 Mat_ ์ƒ์„ฑ ์‹œ <type> ์ƒ๋žต๊ฐ€๋Šฅ
void colorReduce11(cv::Mat image, int div = 64)
{
cv::Mat_<cv::Vec3b> cimage = image;
cv::Mat_<cv::Vec3b>::iterator it = cimage.begin();
cv::Mat_<cv::Vec3b>::iterator itend = cimage.end();
uchar div2 = div >> 1;
for (; it != itend; it++)
{
(*it)[0] = (*it)[0] / div * div + div2;
(*it)[1] = (*it)[1] / div * div + div2;
(*it)[2] = (*it)[2] / div * div + div2;
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•5 at๋งค์†Œ๋“œ ์‚ฌ์šฉํ•˜๊ธฐ ๋น„์ถ”
void colorReduce12(cv::Mat image, int div = 64)
{
int nl = image.rows;
int nc = image.cols;
uchar div2 = div >> 1;
for (int j = 0; j<nl; j++) {
for (int i = 0; i<nc; i++) {
image.at<cv::Vec3b>(j, i)[0] = image.at<cv::Vec3b>(j, i)[0] / div * div + div2;
image.at<cv::Vec3b>(j, i)[1] = image.at<cv::Vec3b>(j, i)[1] / div * div + div2;
image.at<cv::Vec3b>(j, i)[2] = image.at<cv::Vec3b>(j, i)[2] / div * div + div2;
}
}
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•6 Scalar์™€ mask ์‚ฌ์šฉํ•ด์„œ ๋น„ํŠธ์—ฐ์‚ฐ ๊ฐ€์žฅ ๋น ๋ฅธ๋ฐฉ๋ฒ•
void colorReduce13(cv::Mat image, int div = 64)
{
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0) + 0.5);
uchar mask = 0xFF << n;
image = (image & cv::Scalar(mask, mask, mask)) + cv::Scalar(div / 2, div / 2, div / 2);
}
//๋‹ค๋ฅธ๋ฐฉ๋ฒ•7 LUT(Look-up-table) 6๊ฐ•์˜ ๋‚ด์šฉ์„ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•
void colorReduce14(cv::Mat image, int div = 64)
{
cv::Mat lookup(1, 256, CV_8U);
for (int i = 0; i<256; i++)
{
lookup.at<uchar>(i) = i / div * div + div / 2;
}
cv::LUT(image, lookup, image);
}
#define NTESTS 15
#define NITERATIONS 10
int main()
{
cv::Mat image = cv::imread("../images/boldt.jpg");
int64 start = cv::getTickCount();
colorReduce(image, 64);
double duration = (cv::getTickCount() - start) / cv::getTickFrequency();
std::cout << "Duration= " << duration << "secs" << std::endl;
cv::namedWindow("Image");
cv::imshow("Image", image);
cv::waitKey();
image = cv::imread("../images/boldt.jpg");
cv::Mat complete;
start = cv::getTickCount();
colorReduceIO(image, complete, 64);
duration = (cv::getTickCount() - start) / cv::getTickFrequency();
std::cout << "Duration= " << duration << "secs" << std::endl;
cv::namedWindow("ImageIO");
cv::imshow("ImageIO", complete);
cv::waitKey();
int64 t[NTESTS], tinit;
for (int i = 0; i<NTESTS; i++)
t[i] = 0;
cv::Mat images[NTESTS];
cv::Mat result;
typedef void(*FunctionPointer)(cv::Mat, int);
FunctionPointer functions[NTESTS] = { colorReduce, colorReduce1, colorReduce2, colorReduce3, colorReduce4,
colorReduce5, colorReduce6, colorReduce7, colorReduce8, colorReduce9,
colorReduce10, colorReduce11, colorReduce12, colorReduce13, colorReduce14 };
int n = NITERATIONS;
for (int k = 0; k<n; k++) {
std::cout << k << " of " << n << std::endl;
for (int c = 0; c < NTESTS; c++) {
images[c] = cv::imread("../images/boldt.jpg");
tinit = cv::getTickCount();
functions[c](images[c], 64);
t[c] += cv::getTickCount() - tinit;
std::cout << ".";
}
std::cout << std::endl;
}
std::string descriptions[NTESTS] = {
"original version:",
"with dereference operator:",
"using modulo operator:",
"using a binary mask:",
"direct ptr arithmetic:",
"row size recomputation:",
"continuous image:",
"reshape continuous image:",
"with iterators:",
"Vec3b iterators:",
"iterators and mask:",
"iterators from Mat_:",
"at method:",
"overloaded operators:",
"look-up table:",
};
for (int i = 0; i < NTESTS; i++)
{
cv::namedWindow(descriptions[i]);
cv::imshow(descriptions[i], images[i]);
}
std::cout << std::endl << "-------------------------------------------" << std::endl << std::endl;
for (int i = 0; i < NTESTS; i++)
{
std::cout << i << ". " << descriptions[i] << 1000.*t[i] / cv::getTickFrequency() / n << "ms" << std::endl;
}
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 3 - ์ด์›ƒ ์ ‘๊ทผ์œผ๋กœ ์˜์ƒ ์กฐํšŒ>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
void sharpen(const cv::Mat &image, cv::Mat &result)
{
//Mat ํ•จ์ˆ˜ ์žฌํ• ๋‹น์ด ํ•„์š”ํ•  ๊ฒฝ์šฐ๋ฅผ ์œ„ํ•ด์„œ
result.create(image.size(), image.type());
int nchannals = image.channels(); //์ฑ„๋„ ๊ฐœ์ˆ˜ ์–ป๊ธฐ
//๋ชจ๋“  ํ–‰ ๋Œ€์ƒ(์ฒ˜์Œ๊ณผ ๋งˆ์ง€๋ง‰ ์ œ์™ธ)
for (int j = 1; j < image.rows - 1; j++)
{
const uchar* previous = image.ptr<const uchar>(j - 1); //์ด์ „ ํ–‰
const uchar* current = image.ptr<const uchar>(j); //ํ˜„์žฌ ํ–‰
const uchar* next = image.ptr<const uchar>(j + 1); //๋‹ค์Œ ํ–‰
uchar* output = result.ptr<uchar>(j); //๊ฒฐ๊ณผ ํ–‰
for (int i = nchannals; i < (image.cols - 1)*nchannals; i++)
{
//์„ ๋ช…ํ™” ์—ฐ์‚ฐ์ž ์ ์šฉ
*output++ = cv::saturate_cast<uchar>(5 * current[i] - current[i - nchannals] - current[i + nchannals] - previous[i] - next[i]);
//์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์€ ํ™”์†Œ๋ฅผ 0์œผ๋กœ ์„ค์ •
result.row(0).setTo(cv::Scalar(0));
result.row(result.rows - 1).setTo(cv::Scalar(0));
result.col(0).setTo(cv::Scalar(0));
result.col(result.cols - 1).setTo(cv::Scalar(0));
}
}
}
void sharpen2D(const cv::Mat &image, cv::Mat &result)
{
//์ปค๋„ ์ƒ์„ฑ(๋ชจ๋“  ํ•ญ๋ชฉ์„ 0์œผ๋กœ ์ดˆ๊ธฐํ™”)
cv::Mat kernel(3, 3, CV_32F, cv::Scalar(0));
//์ปค๋„ ๊ฐ’์„ ํ• ๋‹น
kernel.at<float>(1, 1) = 5.0;
kernel.at<float>(0, 1) = -1.0;
kernel.at<float>(2, 1) = -1.0;
kernel.at<float>(1, 0) = -1.0;
kernel.at<float>(1, 2) = -1.0;
//์˜์ƒ ํ•„ํ„ฐ๋ง
cv::filter2D(image, result, image.depth(), kernel);
}
void sharpenIterator(const cv::Mat &image, cv::Mat &result)
{
//๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ์ด๋ฏธ์ง€์—ฌ์•ผํ•จ.
CV_Assert(image.type() == CV_8UC1);
//๋ฐ˜๋ณต์ž๋“ค์„ 1ํ–‰์œผ๋กœ ์ดˆ๊ธฐํ™”
cv::Mat_<uchar>::const_iterator it = image.begin<uchar>() + image.cols;
cv::MatConstIterator_<uchar> itend = image.end<uchar>() - image.cols;
cv::Mat_<uchar>::const_iterator itup = image.begin<uchar>();
cv::MatConstIterator_<uchar> itdown = image.begin<uchar>() + 2*image.cols;
//์žฌํ• ๋‹น ํ•„์š”์„ฑ์„ ์œ„ํ•ด
result.create(image.size(), image.type());
//output ๋ฐ˜๋ณต์ž ์„ค์ •
cv::Mat_<uchar>::iterator itout = result.begin<uchar>() + result.cols;
for (; it != itend; ++it, ++itout, ++itup, ++itdown) {
*itout = cv::saturate_cast<uchar>(*it * 5 - *(it - 1) - *(it + 1) - *itup - *itdown);
}
//์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์€ ์˜์—ญ 0์œผ๋กœ
result.row(0).setTo(cv::Scalar(0));
result.row(result.rows - 1).setTo(cv::Scalar(0));
result.col(0).setTo(cv::Scalar(0));
result.col(result.cols - 1).setTo(cv::Scalar(0));
}
int main()
{
cv::Mat image = cv::imread("../images/boldt.jpg");
if (!image.data)
return 0;
cv::Mat result;
double time = static_cast<double>(cv::getTickCount());
sharpen(image, result);
time = (static_cast<double>(cv::getTickCount()) - time) / cv::getTickFrequency();
std::cout << "time= " << time << std::endl;
cv::namedWindow("Image");
cv::imshow("Image", result);
cv::waitKey();
image = cv::imread("../images/boldt.jpg");
time = static_cast<double>(cv::getTickCount());
sharpen2D(image, result);
time = (static_cast<double>(cv::getTickCount()) - time) / cv::getTickFrequency();
std::cout << "time 2D= " << time << std::endl;
cv::namedWindow("Image 2D");
cv::imshow("Image 2D", result);
cv::waitKey();
image = cv::imread("../images/boldt.jpg", 0);
time = static_cast<double>(cv::getTickCount());
sharpenIterator(image, result);
time = (static_cast<double>(cv::getTickCount()) - time) / cv::getTickFrequency();
std::cout << "time 3= " << time << std::endl;
cv::namedWindow("Sharpened Image");
cv::imshow("Sharpened Image", result);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 4 - ๊ฐ„๋‹จํ•œ ์‚ฐ์ˆ  ์—ฐ์‚ฐ ์ˆ˜ํ–‰>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
int main()
{
cv::Mat image1;
cv::Mat image2;
image1 = cv::imread("../images/boldt.jpg");
image2 = cv::imread("../images/rain.jpg");
if (!image1.data)
return 0;
if (!image2.data)
return 0;
cv::namedWindow("Image 1");
cv::imshow("Image 1", image1);
cv::namedWindow("Image 2");
cv::imshow("Image 2", image2);
cv::Mat result;
//๊ทธ๋ƒฅ ๋”ํ•˜๋Š”๊ฒŒ ์•„๋‹Œ ๊ฐ€์ค‘ํ•ฉ addWeighted ๊ฐ€์ค‘์น˜๋ฅผ ๋‘ฌ์„œ ํ•ฉ์น˜๋Š”๊ฑฐ๋ผ ๋” ์ž์—ฐ์Šค๋Ÿฌ์›€
cv::addWeighted(image1, 0.7, image2, 0.9, 0., result);
cv::namedWindow("result");
cv::imshow("result", result);
// ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ด์„œ ADDํ•˜๊ธฐ
result = 0.7* image1 + 0.9*image2;
cv::namedWindow("Result with operators");
cv::imshow("Result with operators", result);
image2 = cv::imread("../images/rain.jpg", 0);
// 3๊ฐœ์˜ Mat๋กœ ์ด๋ค„์ง„ Vector ์„ ์–ธ
std::vector<cv::Mat> planes;
// 3์ฑ„๋„ ์ด๋ฏธ์ง€์˜ ์ฑ„๋„์„ ๋ชจ๋‘ ๋‚˜๋ˆ  3๊ฐœ์˜ ์ด๋ฏธ์ง€๋กœ splitํ•จ์ˆ˜
cv::split(image1, planes);
// ๋ธ”๋ฃจ์ฑ„๋„์— ADDํ•˜๊ธฐ
planes[0] += image2;
// ๋‹ค์‹œ 3์ฑ„๋„ ํ•ฉ์ณ์„œ ํ•˜๋‚˜์˜ 3์ฑ„๋„ ์ด๋ฏธ์ง€๋กœ
cv::merge(planes, result);
cv::namedWindow("Result on blue channel");
cv::imshow("Result on blue channel", result);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 5 - ์˜์ƒ ์žฌ๋งคํ•‘>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
//๋ฌผ๊ฒฐ ํšจ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์˜์ƒ ์žฌ๋งคํ•‘
void wave(const cv::Mat &image, cv::Mat &result)
{
//๋งต ์—ญํ• 
cv::Mat srcX(image.rows, image.cols, CV_32F);
cv::Mat srcY(image.rows, image.cols, CV_32F);
//๋งคํ•‘ ์ƒ์„ฑ
for (int i = 0; i < image.rows; i++) {
for (int j = 0; j < image.cols; j++) {
//ํ™”์†Œ (i, j)์˜ ์ƒˆ๋กœ์šด ์œ„์น˜
srcX.at<float>(i, j) = j; //์—ด์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€
srcY.at<float>(i, j) = i + 5 * sin(j / 10.0); //์›๋ž˜์žˆ๋˜ iํ–‰์˜ ํ™”์†Œ๋ฅผ ๋ฐ”๋กœ ์‚ฌ์ธ ๊ณก์„ ์— ๋”ฐ๋ผ ์˜ฎ๊ธด๋‹ค.
//์ˆ˜ํ‰์œผ๋กœ ๋’ค์ง‘๊ธฐ
//srcX.at<float>(i,j)= image.cols-j-1;
//srcY.at<float>(i,j)= i;
}
}
//๋งคํ•‘ ์ ์šฉ
cv::remap(image, result, srcX, srcY, CV_INTER_LINEAR); //๋งˆ์ง€๋ง‰ ์ธ์ˆ˜ ๋ณด๊ฐ„ํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์„ ํ˜•๋ณด๊ฐ„ ์ ์šฉํ•จ.
}
int main()
{
cv::Mat image = cv::imread("../images/boldt.jpg", 1);
if (!image.data) return 0;
cv::namedWindow("Image");
cv::imshow("Image", image);
cv::Mat result;
wave(image, result);
cv::namedWindow("Remapped image");
cv::imshow("Remapped image", result);
cv::waitKey();
return 0;
}
3. ์˜์ƒ์˜ ์ปฌ๋Ÿฌ ์ฒ˜๋ฆฌ [Processing Images with Classes]
- ์ฝ”๋“œ์— ์ฃผ์„์œผ๋กœ ์„ค๋ช…์„ ๋‹ค๋Š” ์‹์œผ๋กœ ์ •๋ฆฌ.
- Lab ์ƒ‰ ๊ณต๊ฐ„ : https://ko.wikipedia.org/wiki/Lab_%EC%83%89_%EA%B3%B5%EA%B0%84
- ์ฒซ๋ฒˆ ์งธ ์ฝ”๋“œ๋Š” ์˜์ƒ์˜ ๋ชจ๋“ ํ™”์†Œ๋ฅผ ํ™•์ธํ•ด ํŠน์ • ์œ ์‚ฌํ•œ ์ปฌ๋Ÿฌ๋ฅผ ์ฐพ๋Š” ๊ฐ„๋‹จํ•œ ์ปฌ๋Ÿฌ ๋น„๊ต ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ธ๋ฐ, [์ „๋žต ๋””์ž์ธ ํŒจํ„ด]์„ ์‚ฌ์šฉํ•œ๋‹ค.
- ๋‘๋ฒˆ ์งธ ์ฝ”๋“œ๋Š” ์ •์ง€์˜์ƒ์—์„œ ์ „๊ฒฝ ๊ฐ์ฒด๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๊ธฐ์— ๊ฐ€์žฅ ์ข‹์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํ•จ์ˆ˜๋กœ ๊ณ„์‚ฐ์ ์œผ๋กœ ์›Œํ„ฐ์‰๋“œ๋ณด๋‹ค ๋น„์‹ธ์ง€๋งŒ ์ •ํ™•ํ•˜๋‹ค.
๋ถ€๋ถ„ ๋ ˆ์ด๋ธ”๋ง์— ๊ธฐ๋ฐ˜์„ ๋‘๊ณ  ์ „์ฒด ์˜์ƒ์— ๋Œ€ํ•œ ์ „๊ฒฝ/๋ฐฐ๊ฒฝ ์˜์ƒ ๋ถ„ํ• ์„ ๊ฒฐ์ •ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์ „๊ฒฝ์„ ํฌํ•จํ•œ ์‚ฌ๊ฐํ˜•์„ ์‚ฌ์šฉํ•ด ์ „๊ฒฝ/๋ฐฐ๊ฒฝ์„ ๋ ˆ์ด๋ธ”๋งํ•œ๋‹ค.
- ์„ธ๋ฒˆ ์งธ ์ฝ”๋“œ๋Š” ์ฒซ๋ฒˆ ์งธ ์ฝ”๋“œ์•ˆ์— ์žˆ๋‹ค. CIE L*a*b์— ๋Œ€ํ•œ ์ฝ”๋“œ๋กœ RGB ์ปฌ๋Ÿฌ ๊ณต๊ฐ„์€ ๋นจ๊ฐ•,์ดˆ๋ก,ํŒŒ๋ž‘์˜ ๊ฐ€์‚ฐ ์›์ƒ‰์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ๊ธฐ๋ฐ˜์„ ๋‘๊ณ  ์žˆ์œผ๋‚˜,
๋””์ง€ํ„ธ ์˜์ƒ์˜ ๊ธฐ๋ณธ ์ปฌ๋Ÿฌ๊ณต๊ฐ„์ด๋ฉฐ ๊ฑฐ๋ฆฌ ๊ฐ„์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ์ด ์ฃผ์–ด์ง„ ๋‘ ์ปฌ๋Ÿฌ ๊ฐ„์˜ ์œ ์‚ฌ๋„๋ฅผ ์ธก์ •ํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด RGB๋Š” ์ง€๊ฐ์ ์œผ๋กœ๋Š” ๊ท ๋“ฑํ•œ ์ปฌ๋Ÿฌ ๊ณต๊ฐ„์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์–ด์ง„ ๊ฑฐ๋ฆฌ์—์„œ ๋‘ ์ปฌ๋Ÿฌ๊ฐ€ ์•„์ฃผ ๋น„์Šทํ•˜๊ฒŒ ๋ณด์ด๋Š” ๋ฐ˜๋ฉด
๋™์ผํ•œ ๊ฑฐ๋ฆฌ๋กœ ๊ฒฉ๋ฆฌ๋œ ๋‘ ์ปฌ๋Ÿฌ๊ฐ€ ๋งค์šฐ ๋‹ค๋ฅด๊ฒŒ ๋ณด์ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ง€๊ฐ์ ์œผ๋กœ ๊ท ๋“ฑํ•œ ์†์„ฑ์„ ๊ฐ–๋Š” ๋‹ค๋ฅธ ์ปฌ๋Ÿฌ ํ‘œํ˜„์„ ๋„์ž…ํ•œ ๊ฒƒ ์ค‘์— ํ•˜๋‚˜๊ฐ€ CIE L*a*b ์ปฌ๋Ÿฌ ๋ชจ๋ธ์ด๋‹ค.
1. CIE L*a*b
Lab์„ ์‚ฌ์šฉํ•˜๋ฉด ์˜์ƒ ํ™”์†Œ์™€ ๋Œ€์ƒ ์ปฌ๋Ÿฌ ๊ฐ„์˜ ์œ ํด๋ฆฌ๋””์•ˆ ๊ฑฐ๋ฆฌ๋Š” ๋‘ ์ปฌ๋Ÿฌ ๊ฐ„์˜ ์‹œ๊ฐ์  ์œ ์‚ฌ๋„ ์ธก์ •์— ์˜๋ฏธ๊ฐ€ ์žˆ๊ฒŒ ๋  ์ˆ˜ ์žˆ๋‹ค.
Lab์œผ๋กœ ์ž‘์—…ํ•˜๊ธฐ ์œ„ํ•ด ์ด์ „ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•œ ๊ฒƒ์ด ์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•œ ๋‚ด์šฉ์ด๋‹ค.
ํ™”์†Œ์˜ ๊ฐ ๋ฐ๊ธฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” L์ฑ„๋„์€ 0-100์‚ฌ์ด, a b์ฑ„๋„์€ ์ƒ‰๋„(chromaticity) ์„ฑ๋ถ„์— ๋Œ€์‘ํ•˜๊ณ  ๊ฐ’์˜ ๋ฒ”์œ„๋Š” -127~128 ์‚ฌ์ด์— ์žˆ๋‹ค.
2. YCrCb
jPEG ์••์ถ•์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ปฌ๋Ÿฌ๊ณต๊ฐ„์€ 'YCrCb' ์ด๋‹ค.
3. CIE L*u*v
CIE L*u*v ์ปฌ๋Ÿฌ ๊ณต๊ฐ„์€ ์ƒ‰๋„ ์ฑ„๋„์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ํ‘œํ˜„์„ ํ•œ๋‹ค. RGB ์ปฌ๋Ÿฌ ์˜์—ญ์„ ์™œ๊ณกํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€ํ™˜์‹œ ๋น„์„ ํ˜•(๋น„์šฉ์ด ๋งŽ์ด ๋“ค ์ˆ˜ ์žˆ๋‹ค.)๊ณ„์‚ฐ์„ ํ•ด์•ผํ•œ๋‹ค.
4. CIE XYZ
CIE XYZ ์ปฌ๋Ÿฌ ๊ณต๊ฐ„์€ ์žฅ์น˜์— ๋…๋ฆฝ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ์ง€๊ฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์ปฌ๋Ÿฌ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ํ‘œ์ค€ ์ปฌ๋Ÿฌ๊ณต๊ฐ„์ด๋‹ค. Luv ์™€ Lab ๊ณต๊ฐ„์˜ ๊ณ„์‚ฐ ๊ณผ์ •์—์„œ XYZ ์ปฌ๋Ÿฌ ๊ณต๊ฐ„์„ ์ค‘๊ฐ„ ํ‘œํ˜„์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. RGB์™€ XYZ ์ปฌ๋Ÿฌ ๊ณต๊ฐ„ ๊ฐ„์˜ ๋ณ€ํ™˜์€ ๋น„์„ ํ˜• ๊ณ„์‚ฐ์ด๋‹ค.
Y์ฑ„๋„์ด ์˜์ƒ์˜ ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ๋ฒ„์ „์— ๋Œ€์‘ํ•œ๋‹ค๋Š” ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
5. HSV, HLS
HSV๋‚˜ HLS๋Š” ์ปฌ๋Ÿฌ๋ฅผ ์ƒ‰์ƒ ์„ฑ๋ถ„๊ณผ ์ฑ„๋„ ์„ฑ๋ถ„์„ ๋น„๋กฏํ•ด ๋ช…๋„๋‚˜ ๊ด‘๋„ ์„ฑ๋ถ„์„ ๋ถ„ํ•ด ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์ธ๊ฐ„์ด ์ปฌ๋Ÿฌ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•œ ๋งค์šฐ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ฐฉ์‹์ด๊ธฐ๋„ ํ•˜๋‹ค.
6. Gray
์ปฌ๋Ÿฌ์˜์ƒ์„ ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ๋ช…์•”์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๊ฒฐ๊ณผ๋Š” 1์ฑ„๋„ ์˜์ƒ์ด ๋œ๋‹ค. cv::cvtColor(color, gray, CV_BGR2GRAY);
- ๋„ค๋ฒˆ ์งธ ์ฝ”๋“œ๋Š” ์ƒ‰์ƒ, ์ฑ„๋„, ๋ฐ๊ธฐ ๊ฐœ๋…์— ๊ธฐ๋ฐ˜์„ ๋‘” ํ˜„์ƒ์  ์ปฌ๋Ÿฌ ๊ณต๊ฐ„์„ ํ†ตํ•ด ์ปฌ๋Ÿฌ๋ฅผ ๋ฌ˜์‚ฌํ•˜๋Š” ์ˆ˜๋‹จ์ธ ์ƒ‰์ƒ, ์ฑ„๋„, ๋ฐ๊ธฐ์˜ ๊ฐœ๋…์„ ์‚ดํŽด๋ณด๋Š” ์ฝ”๋“œ๋‹ค.
HSV ์ปฌ๋Ÿฌ ๊ณต๊ฐ„ ๊ตฌํ˜„์—์„œ๋Š”
๋ช…๋„๋ฅผ ์„ธ ๊ฐ€์ง€ BGR ์„ฑ๋ถ„์˜ ์ตœ๋Œ“๊ฐ’์œผ๋กœ ์ •์˜ํ•œ๋‹ค. ์ด๋Š” ๋ฐ๊ธฐ ๊ฐœ๋…์„ ์ง€๋‚˜์น˜๊ฒŒ ๋‹จ์ˆœํ™”ํ•œ ๊ตฌํ˜„์ด๋‹ค.
์ฑ„๋„ ๊ณ„์‚ฐ ๋ฐฉ๋ฒ• S = ((max(R,G,B)-min(R,G,B))/max(R,G,B) ์‚ฌ์‹ค ์ฑ„๋„๋Š” BGR ๊ฐ’์˜ ์ตœ๋Œ“๊ฐ’๊ณผ ์ตœ์†Ÿ๊ฐ’์˜ ์ƒ๋Œ€์ ์ธ ์ฐจ์ด๋งŒ ์ธก์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์— (1,0,0)๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ ๊ฒ€๊ฒŒ ๋ณด์—ฌ๋„ ์ฑ„๋„๊ฐ€ 1์ด๋‹ค. ์–ด๋‘์šด ์˜์—ญ์—์„œ์˜ ์ฑ„๋„๋ฅผ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๊ณ , ๊ณ ๋ ค๋„ ํ•˜์ง€ ์•Š์•„์•ผํ•œ๋‹ค.
์ƒ‰์ƒ์€ 0-360์‚ฌ์ด์˜ ๊ฐ๋„ ๊ฐ’์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฉฐ, ๋นจ๊ฐ„์ƒ‰์€ 0๋„๋‹ค. ๋‹จ, 8๋น„ํŠธ ์˜์ƒ์ผ๊ฒฝ์šฐ 255๊ฐ€ ์ตœ๋Œ€์ด๊ธฐ์— ๊ฐ๋„ ๊ฐ’์„ ๋ฐ˜์œผ๋กœ ๋‚˜๋ˆˆ๋‹ค. 0-180
HSB ์ปฌ๋Ÿฌ ๊ณต๊ฐ„์€ ๊ฐ ์ ์ด ๋‚ด๋ถ€์— ํŠน์ •ํ•œ ์ปฌ๋Ÿฌ์— ๋Œ€์‘ํ•˜๋Š” ์›์ถ”๋กœ ์ž์ฃผ ํ‘œํ˜„๋œ๋‹ค.
๊ฐ์ด ์ง„ ์œ„์น˜๋Š” ์ปฌ๋Ÿฌ์˜ ์ƒ‰์ƒ(H)์— ๋Œ€์‘ํ•˜๊ณ , ์ฑ„๋„๋Š” ์ค‘์‹ฌ ์ถ•์œผ๋กœ๋ถ€ํ„ฐ์˜ ๊ฑฐ๋ฆฌ(S)์ด๋ฉฐ, ๋ฐ๊ธฐ๋Š” ๋†’์ด(B)๋กœ ์ฃผ์–ด์ง„๋‹ค. ์›์ถ”์˜ ๊ผญ๋Œ€๊ธฐ๋Š” ์ƒ‰์ƒ๊ณผ ์ฑ„๋„๊ฐ€ ์ •์˜๋˜์ง€ ์•Š์€ ๊ฒ€์€์ƒ‰์— ๋Œ€์‘ํ•œ๋‹ค.
์ƒ‰์ƒ ์ฑ„๋„(HS)๋ฅผ ์‚ฌ์šฉํ•ด ํ”ผ๋ถ€์ƒ‰ ๊ฒ€์ถœ ํ…Œ์ŠคํŠธ๋กœ ๋งˆ๋ฌด๋ฆฌ ํ•œ๋‹ค.
<์ฝ”๋“œ 1 - ์ „๋žต ํŒจํ„ด์„ ์ด์šฉํ•œ ์ปฌ๋Ÿฌ ๋น„๊ต (3๊ฐœ์˜ ํŒŒ์ผ)>
================ 1 ch03-1.cpp ==================
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include "colordetector.h"
int main()
{
//1. ์˜์ƒ์ฒ˜๋ฆฌ๊ธฐ ๊ฐ์ฒด ์ƒ์„ฑ
ColorDetector cdetect;
//2. ์ž…๋ ฅ์˜์ƒ ์ฝ๊ธฐ
cv::Mat image = cv::imread("../images/boldt.jpg");
if (image.empty()) return 0;
cv::namedWindow("Original Image");
cv::imshow("Original Image", image);
//3. ์ž…๋ ฅํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •
cdetect.setTargetColor(230, 190, 130); //ํ‘ธ๋ฅธ ํ•˜๋Š˜์ฐพ๊ธฐ
//4. ์˜์ƒ์„ ์ฒ˜๋ฆฌ ํ•œ ํ›„ ๊ฒฐ๊ณผ๋ฅผ ์ฐฝ์— ๋„์›€
cv::Mat result = cdetect.process(image);
cv::namedWindow("result");
cv::imshow("result", result);
//or ํ•จ์ˆ˜์ž ์‚ฌ์šฉํ•˜๊ธฐ
//์—ฌ๊ธฐ์„œ ๊ฑฐ๋ฆฌ๋Š” Lab ์ปฌ๋Ÿฌ ๊ณต๊ฐ„์œผ๋กœ ์ธก์ •๋œ๋‹ค.
ColorDetector colordetector(230, 190, 130, //์ƒ‰
45, true); //Lab ๊ฒฝ๊ณ„์„ 
result = colordetector(image);
cv::namedWindow("result (functor)");
cv::imshow("result (functor)", result);
//floodFill ํ•จ์ˆ˜ ํ…Œ์ŠคํŠธ
cv::floodFill(image, //์ž…๋ ฅ/๊ฒฐ๊ณผ ์˜์ƒ
cv::Point(100, 50), //์ดˆ๊ธฐ ์ 
cv::Scalar(255, 255, 255), //๋‹ค์‹œ ๊ทธ๋ฆฐ ์ปฌ๋Ÿฌ
(cv::Rect*)0, //๋‹ค์‹œ ๊ทธ๋ฆฐ ์ง‘ํ•ฉ์˜ ๊ฒฝ๊ณ„ ์‚ฌ๊ฐํ˜•
cv::Scalar(35, 35, 35), //๋‚ฎ์€ ์ฐจ์ด ๊ฒฝ๊ณ„๊ฐ’
cv::Scalar(35, 35, 35), //๋†’์€ ์ฐจ์ด ๊ฒฝ๊ณ„๊ฐ’
cv::FLOODFILL_FIXED_RANGE); //์‹œ๋“œ ํ™”์†Œ์™€ ๋น„๊ตํ•  ํ™”์†Œ
result = colordetector(image);
cv::namedWindow("Flood Fill result");
cv::imshow("Flood Fill result", image);
//์ƒ‰ ๊ณต๊ฐ„์˜ ์†์„ฑ๋“ค์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ๋‹จ์ˆœํ•œ ์˜์ƒ ์ƒ์„ฑ
cv::Mat colors(100, 300, CV_8UC3, cv::Scalar(100, 200, 150));
cv::Mat range = colors.colRange(0, 100);
range = range + cv::Scalar(10, 10, 10);
cv::namedWindow("3 colors");
cv::imshow("3 colors", colors);
cv::waitKey();
range = colors.colRange(200, 300);
range = range + cv::Scalar(-10, -10, 10);
cv::imshow("3 colors", colors);
cv::Mat labImage(100, 300, CV_8UC3, cv::Scalar(100, 200, 150));
cv::cvtColor(labImage, labImage, CV_BGR2Lab);
range = labImage.colRange(0, 100);
range = range + cv::Scalar(10, 10, 10);
cv::namedWindow("3 colors (Lab)");
cv::imshow("3 colors (Lab)", labImage);
cv::waitKey();
range = labImage.colRange(200, 300);
range = range + cv::Scalar(-10, -10, 10);
cv::imshow("3 colors (Lab)", labImage);
cv::waitKey();
cv::cvtColor(labImage, labImage, CV_BGR2Lab);
cv::imshow("3 colors (Lab)", labImage);
//๋ฐ๊ธฐ(๋ช…๋„) vs ํœ˜๋„
cv::Mat grayLevels(100, 256, CV_8UC3);
for (int i = 0; i < 256; i++) {
grayLevels.col(i) = cv::Scalar(i, i, i);
}
range = grayLevels.rowRange(50, 100);
cv::Mat channels[3];
cv::split(range, channels);
channels[1] = 128;
channels[2] = 128;
cv::merge(channels, 3, range);
cv::cvtColor(range, range, CV_Lab2BGR);
cv::namedWindow("Luminance vs Brightness");
cv::imshow("Luminance vs Brightness", grayLevels);
cv::waitKey();
return 0;
}
================ 2 colordetector.h ==================
#if !defined COLORDETECT
#define COLORDETECT
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
class ColorDetector {
private:
//์ตœ์†Œ ํ—ˆ์šฉ๊ฑฐ๋ฆฌ
int maxDist;
//๋Œ€์ƒ ์ปฌ๋Ÿฌ
cv::Vec3b target;
//๋ณ€ํ™˜๋œ ์˜์ƒ์˜ ์ƒ‰์„ ํฌํ•จํ•œ ์˜์ƒ
cv::Mat converted;
bool useLab;
//๊ฒฐ๊ณผ ์ด์ง„ ๋งต์„ ํฌํ•จํ•˜๋Š” ์˜์ƒ
cv::Mat result;
public:
//๋นˆ ์ƒ์„ฑ์ž
//์—ฌ๊ธฐ์„œ ๊ธฐ๋ณธ ํŒŒ๋ผ๋ฏธํ„ฐ ์ดˆ๊ธฐํ™”
ColorDetector() : maxDist(100), target(0, 0, 0), useLab(false) {}
//Lab ์ปฌ๋Ÿฌ ๊ณต๊ฐ„ ์˜ˆ์ œ๋ฅผ ์œ„ํ•œ ์ถ”๊ฐ€ ์ƒ์„ฑ์ž
ColorDetector(bool useLab) : maxDist(100), target(0,0,0), useLab(useLab) {}
//์™„์ „ ์ƒ์„ฑ์ž
ColorDetector(uchar blue, uchar green, uchar red, int maxDist = 100, bool useLab= false) : maxDist(maxDist), useLab(useLab) {
//๋Œ€์ƒ ์ปฌ๋Ÿฌ
setTargetColor(blue, green, red);
}
//๋Œ€์ƒ ์ปฌ๋Ÿฌ๋กœ๋ถ€ํ„ฐ์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ
int getDistanceToTargetColor(const cv::Vec3b& color) const {
return getColorDistance(color, target);
}
//๋‘ ์ปฌ๋Ÿฌ ๊ฐ„์˜ ๋„์‹œ ๋ธ”๋Ÿญ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ
int getColorDistance(const cv::Vec3b& color1, const cv::Vec3b& color2) const {
return abs(color1[0] - color2[0]) + abs(color1[1] - color2[1]) + abs(color1[2] - color2[2]);
//Or: ์œ ํด๋ฆฌ๋””์•ˆ ๋†ˆ์„ ๊ณ„์‚ฐํ•˜๋Š” ํ•จ์ˆ˜ norm() ๋บ„์ƒ˜๊ฒฐ๊ณผ๊ฐ€ intํ˜•์ด๋ผ Vec3i ์‚ฌ์šฉ
//return static_cast<int>(cv::norm<int,3>(cv::Vec3i(color[0]-color2[0],color[1]-color2[1],color[2]-color2[2])));
//Or: ์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ํ‹€๋ฆฐ ์˜ˆ return static_cast<int>(cv::norm<uchar,3>(color-target)); ์‚ฐ์ˆ ์—ฐ์‚ฐํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
//cv::Vec3b dist;
//cv::absdiff(color,color2,dist);
//return cv::sum(dist)[0];
}
//์˜์ƒ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค. ํ•œ๊ฐœ์˜ ์ฑ„๋„์„ ๊ฐ€์ง„ ์ด์ง„ ์˜์ƒ์„ ๋ฐ˜ํ™˜ํ•จ.
cv::Mat process(const cv::Mat &image);
cv::Mat operator()(const cv::Mat &image) {
cv::Mat input;
if (useLab) {
cv::cvtColor(image, input, CV_BGR2Lab);
}
else {
input = image;
}
cv::Mat output;
//๋Œ€์ƒ ์ปฌ๋Ÿฌ์™€ ์ ˆ๋Œ€์ฐจ ๊ณ„์‚ฐ
cv::absdiff(input, cv::Scalar(target), output);
//์ฑ„๋„์„ ์„ธ ์˜์ƒ์œผ๋กœ ๋ถ„๋ฆฌ
std::vector<cv::Mat> images;
cv::split(output, images);
//์ƒˆ ์ฑ„๋„์„ ๋”ํ•จ(์—ฌ๊ธฐ์„œ saturation(saturate_cast)๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ
output = images[0] + images[1] + images[2];
//๊ฒฝ๊ณ„๊ฐ’ ํ—ˆ์šฉ
cv::threshold(output, //์ž…๋ ฅ์˜์ƒ
output, //๊ฒฐ๊ณผ์˜์ƒ
maxDist, //๊ฒฝ๊ณ„๊ฐ’(256๋ฏธ๋งŒ์ด์—ฌ์•ผ ํ•จ)
255, //์ตœ๋Œ“๊ฐ’
cv::THRESH_BINARY_INV); //๊ฒฝ๊ณ„ํ™” ๋ชจ๋“œ, ๊ฒฝ๊ณ„๊ฐ’๋ณด๋‹ค ๊ฐ™๊ฑฐ๋‚˜ ์ž‘์œผ๋ฉด ์ •์˜๋œ ์ตœ๋Œ“๊ฐ’์„ ํ• ๋‹นํ•˜๋Š” ๋ฐ˜์ „๋ชจ๋“œ ๊ทธ ์™ธ์— THRESH_BINARY=0, THRESH_TOZERO ๋“ฑ์ด ์žˆ๋‹ค.
return output;
}
//getters and setters
//์ปฌ๋Ÿฌ ๊ฑฐ๋ฆฌ ๊ฒฝ๊ณ„๊ฐ’ ์„ค์ •
//๊ฒฝ๊ณ„ ๊ฐ’์€ ์–‘์ˆ˜์ด์–ด์•ผ ํ•˜๋ฉฐ, ์•„๋‹ˆ๋ผ๋ฉด ๊ฑฐ๋ฆฌ ๊ฒฝ๊ณ„ ๊ฐ’์„ 0์œผ๋กœ ์„ค์ •
void setColorDistanceThreshold(int distance) {
if (distance < 0) distance = 0;
maxDist = distance;
}
//์ปฌ๋Ÿฌ ๊ฑฐ๋ฆฌ ๊ฒฝ๊ณ„ ๊ฐ’ ์–ป๊ธฐ
int getColorDistanceThreshold() const {
return maxDist;
}
//๊ฒ€์ถœํ•  ์ปฌ๋Ÿฌ ์„ค์ •
void setTargetColor(uchar blue, uchar green, uchar red) {
//BGR ์ˆœ์„œ
target = cv::Vec3b(blue, green, red);
if (useLab) {
//์ž„์‹œ 1 ํ”ฝ์…€ ์˜์ƒ ์ƒ์„ฑ
cv::Mat tmp(1, 1, CV_8UC3);
tmp.at<cv::Vec3b>(0, 0) = cv::Vec3b(blue, green, red);
//๋Œ€์ƒ์„ Lab ์ปฌ๋Ÿฌ ๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜
cv::cvtColor(tmp, tmp, CV_BGR2Lab);
target = tmp.at<cv::Vec3b>(0, 0);
}
}
//์˜ค๋ฒ„๋กœ๋”ฉ
void setTargetColor(cv::Vec3b color) {
target = color;
}
//๊ฒ€์ถœํ•  ์ปฌ๋Ÿฌ ์–ป๊ธฐ
cv::Vec3b getTargetColor() const {
return target;
}
};
#endif
================ 3 colordetector.cpp ==================
#include "colordetector.h"
#include <vector>
cv::Mat ColorDetector::process(const cv::Mat &image) {
//ํ•„์š”ํ•˜๋‹ค๋ฉด ์ด์ง„ ๋งต ์žฌํ• ๋‹น
//์ž…๋ ฅ ์˜์ƒ์˜ ํฌ๊ธฐ์™€ ๊ฐ™์ง€๋งŒ 1์ฑ„๋„์ž„
result.create(image.size(), CV_8U);
//ํ•„์š”ํ•˜๋‹ค๋ฉด Lab์ปฌ๋Ÿฌ ๊ณต๊ฐ„์œผ๋กœ ๋ณ€๊ฒฝ
if (useLab)
cv::cvtColor(image, converted, CV_BGR2Lab);
//๋ฐ˜๋ณต์ž ์–ป๊ธฐ
cv::Mat_<cv::Vec3b>::const_iterator it = image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iterator itend = image.end<cv::Vec3b>();
//๊ฒฐ๊ณผ ์˜์ƒ์˜ ๋Œ€ํ•œ ๋ฐ˜๋ณต์ž ์–ป๊ธฐ
cv::Mat_<uchar>::iterator itout = result.begin<uchar>();
//๋ณ€ํ™˜๋œ ์˜์ƒ์„ ์œ„ํ•œ ๋ฐ˜๋ณต์ž ์–ป๊ธฐ
if (useLab) {
it = converted.begin<cv::Vec3b>();
itend = converted.end<cv::Vec3b>();
}
//๊ฐ ํ™”์†Œ์— ๋Œ€ํ•ด ๋ฐ˜๋ณต
for (; it != itend; ++it, ++itout) {
//๋Œ€์ƒ ์ปฌ๋Ÿฌ๋กœ๋ถ€ํ„ฐ์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ
if (getDistanceToTargetColor(*it) <= maxDist) {
*itout = 255;
}
else {
*itout = 0;
}
}
return result;
}
<์ฝ”๋“œ 2 - ๊ทธ๋žฉ์ปท ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์˜์ƒ ๋ถ„ํ• >
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main()
{
cv::Mat image = cv::imread("../images/boldt.jpg");
if (!image.data)
return 0;
cv::namedWindow("Original Image");
cv::imshow("Original Image", image);
//๊ฒฝ๊ณ„ ์‚ฌ๊ฐํ˜• ์ •์˜
//๊ฒฝ๊ณ„ ์‚ฌ๊ฐํ˜• ๋ฐ”๊นฅ์— ์žˆ๋Š” ํ™”์†Œ๋ฅผ ๋ฐฐ๊ฒฝ์œผ๋กœ ๋ ˆ์ด๋ธ”๋ง
cv::Rect rectangle(50, 25, 210, 180);
cv::Mat result; //๋ถ„ํ•  (๊ฐ€๋Šฅํ•œ ๊ฐ’์€ 4๊ฐœ)
cv::Mat bgModel, fgModel; //๋ชจ๋ธ (๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ)
//๊ทธ๋žฉ์ปท ๋ถ„ํ• 
cv::grabCut(image, //์ž…๋ ฅ ์˜์ƒ
result, //๋ถ„ํ•  ๊ฒฐ๊ณผ
rectangle, //์ „๊ฒฝ์„ ํฌํ•จํ•œ ์‚ฌ๊ฐํ˜•
bgModel, fgModel, //๋ชจ๋ธ
5, //๋ฐ˜๋ณต ํšŸ์ˆ˜
cv::GC_INIT_WITH_RECT); //์‚ฌ๊ฐํ˜• ์‚ฌ์šฉ
//์ž…๋ ฅ/๊ฒฐ๊ณผ ๋ถ„ํ•  ์˜์ƒ์€ 4๊ฐ€์ง€ ๊ฐ’ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ฐ–๊ฒŒ ๋œ๋‹ค.
//cv::GC_BGD = 0 ๋ฐฐ๊ฒฝ์— ๋ถ„๋ช…ํžˆ ์†ํ•˜๋Š” ํ™”์†Œ(์˜ˆ๋ฅผ๋“ค์–ด ์‚ฌ๊ฐํ˜• ๋ฐ–์— ์žˆ๋Š” ํ™”์†Œ),
//cv::GC_FGD = 1 ์ „๊ฒฝ์— ๋ถ„๋ช…ํžˆ ์†ํ•˜๋Š” ํ™”์†Œ(์˜ˆ๋ฅผ๋“ค์–ด ์•„๋ž˜ ์˜ˆ์ œ์—๋Š” ์—†์Œ),
//cv::GC_PR_BGD = 2 ์•„๋งˆ๋„ ๋ฐฐ๊ฒฝ์— ์†ํ•  ๋“ฏํ•œ ํ™”์†Œ์— ๋Œ€ํ•œ ๊ฐ’
//cv::GC_PR_FGD = 3 ์•„๋งˆ๋„ ์ „๊ฒฝ์— ์†ํ•  ๋“ฏํ•œ ํ™”์†Œ์— ๋Œ€ํ•œ ๊ฐ’(์˜ˆ๋ฅผ๋“ค์–ด ์•„๋ž˜ ์˜ˆ์ œ์—์„œ ์‚ฌ๊ฐํ˜• ๋‚ด๋ถ€์— ์žˆ๋Š” ํ™”์†Œ๋ฅผ ์–ป๊ธฐ ์œ„ํ•œ ์ดˆ๊ธฐ๊ฐ’)
//์ „๊ฒฝ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๊ฒŒ ํ‘œ์‹๋œ ํ™”์†Œ ์–ป๊ธฐ, 3์ธ ํ™”์†Œ
cv::compare(result, cv::GC_PR_FGD, result, cv::CMP_EQ);
//or ๋น„ํŠธ๋ณ„ ๋…ผ๋ฆฌ๊ณฑ ์—ฐ์‚ฐ์œผ๋กœ ์ฒซ ๋ฒˆ์งธ ๋น„ํŠธ 0(์ „๊ฒฝ), 1(๋ฐฐ๊ฒฝ) ์ด๋ƒ๋กœ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ์Œ
//result = result & 1;
//๊ฒฐ๊ณผ ์˜์ƒ ์ƒ์„ฑ
//๋ชจ๋‘ ํฐ์ƒ‰์ธ ์˜์ƒ ์ƒ์„ฑ
cv::Mat foreground(image.size(), CV_8UC3, cv::Scalar(255, 255, 255));
//๋งˆ์Šคํฌ๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐฐ๊ฒฝ ํ™”์†Œ๋ฅผ ๋ณต์‚ฌํ•˜์ง€ ์•Š์Œ
image.copyTo(foreground, result);
//์›๋ณธ ์ด๋ฏธ์ง€์— ๊ฒฝ๊ณ„ ์‚ฌ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ
cv::rectangle(image, rectangle, cv::Scalar(255, 255, 255), 1);
cv::namedWindow("Image with rectangle");
cv::imshow("Image with rectangle", image);
cv::namedWindow("Foreground object");
cv::imshow("Foreground object", foreground);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 3 - ์ปฌ๋Ÿฌ ํ‘œํ˜„ ๋ฐ˜ํ™˜>
//๋”ฐ๋กœ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ์ฝ”๋“œ1๋ฅผ ์ˆ˜์ •ํ•ด์„œ ํ‘œํ˜„. ๋‹ค์–‘ํ•œ ์ปฌ๋Ÿฌ ์ฑ„๋„์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ์œ„์— ์„ค๋ช…ํ–ˆ๋‹ค.
<์ฝ”๋“œ 4 - ์ƒ‰์ƒ, ์ฑ„๋„, ๋ฐ๊ธฐ๋กœ ์ปฌ๋Ÿฌ ํ‘œํ˜„>
#include <iostream>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
//ํ”ผ๋ถ€์ธ์ง€ ํ™•์ธํ•˜๋Š” ํ•จ์ˆ˜
void detectHScolor(const cv::Mat& image, //์ž…๋ ฅ ์˜์ƒ
double minHue, double maxHue, //์ƒ‰์ƒ ๊ฐ„๊ฒฉ
double minSat, double maxSat, //์ฑ„๋„ ๊ฐ„๊ฒฉ
cv::Mat& mask) //์ถœ๋ ฅ ๋งˆ์Šคํฌ
{
//HSV ๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
//3์ฑ„๋„์„ 3๊ฐœ์˜ ์˜์ƒ์œผ๋กœ ๋ถ„๋ฆฌ
std::vector<cv::Mat> channels;
cv::split(hsv, channels);
//channels[0]์€ ์ƒ‰์ƒ
//channels[1]์€ ์ฑ„๋„
//channels[2]์€ ๋ช…๋„
//์ƒ‰์ƒ ๋งˆ์Šคํ‚น
cv::Mat mask1; //maxHue ์ดํ•˜
//์ƒ‰์ƒ ๊ฐ’์ด maxHue๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์œผ๋ฉด 255๋ฅผ ์ ์šฉํ•œ๋‹ค
cv::threshold(channels[0], mask1, maxHue, 255, cv::THRESH_BINARY_INV);
cv::Mat mask2; //minHue ์ด์ƒ
//minHue๋ณด๋‹ค ํฌ๋ฉด 255 ์ž‘์œผ๋ฉด 0์„ ์ ์šฉํ•œ๋‹ค
cv::threshold(channels[0], mask2, minHue, 255, cv::THRESH_BINARY);
cv::Mat hueMask; //์ƒ‰์ƒ ๋งˆ์Šคํฌ
if (minHue < maxHue)
hueMask = mask1 & mask2;
else //๊ฐ„๊ฒฉ์ด 0๋„ ์ถ•๊ณผ ๊ต์ฐจํ•˜๋ฉด
hueMask = mask1 | mask2;
//์ฑ„๋„ ๋งˆ์Šคํ‚น
cv::threshold(channels[1], mask1, maxSat, 255, cv::THRESH_BINARY_INV); //maxSat ์ดํ•˜ ์ƒ‰์ƒ ๊ฐ’์ด maxSat๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์œผ๋ฉด 255๋ฅผ ์ ์šฉํ•œ๋‹ค
cv::threshold(channels[1], mask1, minSat, 255, cv::THRESH_BINARY); //mixSat ์ด์ƒ minSat๋ณด๋‹ค ํฌ๋ฉด 255 ์ž‘์œผ๋ฉด 0์„ ์ ์šฉํ•œ๋‹ค
cv::Mat satMask; //์ฑ„๋„ ๋งˆ์Šคํฌ
satMask = mask1 & mask2; //์ฑ„๋„๋Š” ๊ต์ฐจํ•  ์ผ์ด ์—†์œผ๋ฏ€๋กœ ์กฐ๊ฑด๋ฌธ ํ•„์š”์—†์Œ
//๋งˆ์Šคํฌ ์กฐํ•ฉ
mask = hueMask & satMask;
}
int main()
{
cv::Mat image = cv::imread("../images/boldt.jpg");
if (image.empty())
return 0;
cv::namedWindow("Original Image");
cv::imshow("Original Image", image);
//HSV ๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
//3์ฑ„๋„์„ 3๊ฐœ์˜ ์˜์ƒ์œผ๋กœ ๋ถ„๋ฆฌ
std::vector<cv::Mat> channels;
cv::split(hsv, channels);
//channels[0]์€ ์ƒ‰์ƒ
//channels[1]์€ ์ฑ„๋„
//channels[2]์€ ๋ช…๋„
//๋ช…๋„ ๊ฐ’
cv::namedWindow("Value");
cv::imshow("Value", channels[2]);
//์ฑ„๋„ ๊ฐ’
cv::namedWindow("Saturation");
cv::imshow("Saturation", channels[1]);
//์ƒ‰์ƒ ๊ฐ’
cv::namedWindow("Hue");
cv::imshow("Hue", channels[0]);
//๋ณ€๊ฒฝ ์˜์ƒ์„ ๋‹ด์„ ์ƒˆ๋กœ์šด ๋นˆ ์˜์ƒ ์ƒ์„ฑ
cv::Mat newImage;
//์›๋ž˜ ๋ช…๋„๊ฐ’์„ ๋‹ด์•„๋‘˜ ์ž„์‹œ ์˜์ƒ ์ƒ์„ฑ
cv::Mat tmp(channels[2].clone());
//๋ช…๋„ ๊ฐ’ ๋ณ€๊ฒฝํ•˜๊ธฐ, ๋ช…๋„ ์ฑ„๋„์˜ ๋ชจ๋“  ํ™”์†Œ๋Š” 255๊ฐ€ ๋จ
channels[2] = 255;
//ํ•ฉ์น˜๊ณ  BGR๋กœ ๋‹ค์‹œ ๋ณ€ํ™˜
cv::merge(channels, hsv);
cv::cvtColor(hsv, newImage, CV_HSV2BGR);
cv::namedWindow("Fixed Value Image");
cv::imshow("Fixed Value Image", newImage);
//์ฑ„๋„ ๊ฐ’ ๋ณ€๊ฒฝํ•˜๊ธฐ
channels[1] = 255;
channels[2] = tmp;
cv::merge(channels, hsv);
cv::cvtColor(hsv, newImage, CV_HSV2BGR);
cv::namedWindow("Fixed Saturation Image");
cv::imshow("Fixed Saturation Image", newImage);
//์ฑ„๋„์™€ ๋ช…๋„๊ฐ’ ๋ณ€๊ฒฝํ•˜๊ธฐ
channels[1] = 255;
channels[2] = 255;
cv::merge(channels, hsv);
cv::cvtColor(hsv, newImage, CV_HSV2BGR);
cv::namedWindow("Fixed Saturation/Value Image");
cv::imshow("Fixed Saturation/Value Image", newImage);
//์„œ๋กœ ๋‹ค๋ฅธ ์ƒ‰์ƒ๊ณผ ์ฑ„๋„ ์กฐํ•ฉ์„ ๋ณด์—ฌ์ฃผ๋Š” ์ธ๊ณต์ ์ธ HS ์˜์ƒ
cv::Mat hs(128, 360, CV_8UC3);
for (int h = 0; h < 360; h++)
{
for (int s = 0; s < 128; s++)
{
hs.at<cv::Vec3b>(s, h)[0] = h / 2; //๋ชจ๋“  ์ƒ‰์ƒ ๊ฐ’
hs.at<cv::Vec3b>(s, h)[1] = 255-s*2;//๋†’์€ ์ฑ„ํ† ๋ถ€ํ„ฐ ๋‚ฎ์€ ์ฑ„๋„๊นŒ์ง€
hs.at<cv::Vec3b>(s, h)[2] = 255; //๋ฐ๊ธฐ ์ƒ์ˆ˜ ๊ฐ’
}
}
cv::cvtColor(hs, newImage, CV_HSV2BGR);
cv::namedWindow("Hue/Saturation");
cv::imshow("Hue/Saturation", newImage);
cv::waitKey();
//ํ”ผ๋ถ€์ƒ‰ ๊ฒ€์ถœ ํ…Œ์ŠคํŠธ
image = cv::imread("../images/girl.jpg");
if (image.empty())
return 0;
cv::imshow("Original Image", image);
cv::waitKey();
//ํ”ผ๋ถ€์ƒ‰ ๊ฒ€์ถœ
cv::Mat mask;
detectHScolor(image,
160, 10, //320๋„๋ถ€ํ„ฐ 20๋„๊นŒ์ง€์˜ ์ƒ‰์ƒ
25, 166, //-0.1๋ถ€ํ„ฐ 0.65๊นŒ์ง€์˜ ์ฑ„๋„
mask);
//๋งˆ์Šคํฌ ๋œ ์˜์ƒ ๋ณด์—ฌ์ฃผ๊ธฐ
cv::Mat detected(image.size(), CV_8UC3, cv::Scalar(0, 0, 0));
image.copyTo(detected, mask);
cv::namedWindow("Detection result");
cv::imshow("Detection result", detected);
cv::waitKey();
//ํœ˜๋„์™€ ๋ช…๋„ ๋น„๊ตํ•˜๋Š” ํ…Œ์ŠคํŠธ
//๊ธด ์ค„์˜ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
cv::Mat linear(100, 256, CV_8U);
for (int i = 0; i<256; i++)
linear.col(i) = i;
//Lab ์ƒ‰ ๊ณต๊ฐ„ ์ด๋ฏธ์ง€ ์ƒ์„ฑ
linear.copyTo(channels[0]);
cv::Mat constante(100, 256, CV_8U, cv::Scalar(128));
constante.copyTo(channels[1]);
constante.copyTo(channels[2]);
cv::merge(channels, image);
//BGR๋กœ ๋‹ค์‹œ ๋ณ€ํ™˜
cv::Mat brightness;
cv::cvtColor(image, brightness, CV_Lab2BGR);
cv::split(brightness, channels);
//๊ฒฐํ•ฉํ•œ ์ด๋ฏธ์ง€ ์ƒ์„ฑ
cv::Mat combined(200, 256, CV_8U);
cv::Mat half1(combined, cv::Rect(0, 0, 256, 100));
linear.copyTo(half1);
cv::Mat half2(combined, cv::Rect(0, 100, 256, 100));
channels[0].copyTo(half2);
cv::namedWindow("Luminance vs Brightness");
cv::imshow("Luminance vs Brightness", combined);
cv::waitKey();
return 0;
}
4. ํžˆ์Šคํ† ๊ทธ๋žจ์œผ๋กœ ํ™”์†Œ ์„ธ๊ธฐ [Counting the Pixels with Histograms]
- ํžˆ์Šคํ† ๊ทธ๋žจ์ด๋ž€ ์˜์ƒ์—์„œ ํŠน์ •ํ•œ ๊ฐ’์„ ๊ฐ–๋Š” ํ™”์†Œ ๊ฐœ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋‹จ์ˆœํ•œ ํ…Œ์ด๋ธ”์ด๋‹ค. ์˜์ƒ์˜ ๋‚ด์šฉ์„ ํŠน์„ฑํ™”ํ•˜๊ณ , ์˜์ƒ ๋‚ด์˜ ํŠน์ • ๊ฐ์ฒด๋‚˜ ์งˆ๊ฐ์„ ๊ฒ€์ถœํ•  ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.
- ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ์€ 256๊ฐœ์˜ ํ•ญ๋ชฉ(bin)์„ ๊ฐ–๋Š”๋‹ค. bin 0์€ ๊ฐ’์ด 0์ธ ํ™”์†Œ ๊ฐœ์ˆ˜๋ฅผ ์ œ๊ณต, ... ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ๋ชจ๋“  ํ•ญ๋ชฉ์„ ํ•ฉํ•˜๋ฉด ํ™”์†Œ์˜ ๊ฐœ์ˆ˜์ด๋‹ค.
- bin์˜ ํ•ฉ์ด 1์ด ๋˜๋„๋ก ํžˆ์Šคํ† ๊ทธ๋žจ์„ ์ •๊ทœํ™”ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋Ÿด ๊ฒฝ์šฐ, ๊ฐ bin์€ ์˜์ƒ ๋‚ด ํŠน์ • ๊ฐ’์„ ๊ฐ–๋Š” ํ™”์†Œ์˜ ๋น„์œจ์„ ์ œ๊ณตํ•œ๋‹ค.
- cv::calcHist() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํžˆ์Šคํ† ๊ทธ๋žจ์„ ์‰ฝ๊ฒŒ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž„์˜ ํ™”์†Œ ๊ฐ’ ํƒ€์ž…๊ณผ ๋ฒ”์œ„๋ฅผ ๊ฐ–๋Š” ๋‹ค์ฑ„๋„ ์˜์ƒ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋Š” ์ผ๋ฐ˜์ ์ธ ํ•จ์ˆ˜์ด๋‹ค.
- cv::LUT()๋Š” ์ „์ฒด์ ์œผ๋กœ ๊ฐ’์„ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋‹ค. ๋ช…๋„๊ฐ’์„ ์ƒˆ๋กœ์šด ๋ช…๋„๊ฐ’์œผ๋กœ ๋ณ€ํ˜•ํ•˜๋Š”๋ฐ ์œ ์šฉํ•˜๋ฉฐ, imin = 0, ์ค‘๊ฐ„๊ฐ’ ์„ ํ˜•, imax = 255 ์ด๋Ÿฐ์‹์œผ๋กœ _/๏ฟฃ ๋ช…๋„๊ฐ’์„ ๋Š˜๋ฆด ์ˆ˜ ์žˆ๋‹ค. \ ์ด๋Ÿฐ์‹์œผ๋กœ ์—ญ์œผ๋กœ ๋งคํ•‘ํ•˜๋ฉด ๋ช…๋„๊ฐ€ ์—ญ์ƒ์ด ๋œ๋‹ค.
- ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๋Š˜๋ฆด ์ˆ˜๋„ ์žˆ๋Š”๋ฐ, ์ž˜๋ผ์„œ(%or๋นˆ์ˆ˜ imax, imin) LUT()๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜์ธ equalizeHist()๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
- ํžˆ์Šคํ† ๊ทธ๋žจ ์—ญํˆฌ์˜์œผ๋กœ ํŠน์ • ์˜์ƒ ๋‚ด์šฉ์„ ๊ฒ€์ถœ(์ฐพ๋Š”)ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ 4๊ฐ€์ง€๋ฅผ ๋‹ค๋ฃฌ๋‹ค.
[ํ‘๋ฐฑ] ROI -> ํžˆ์Šคํ† ๊ทธ๋žจ ์ฐพ๊ธฐ -> ํžˆ์Šคํ† ๊ทธ๋žจ ์„ค์ •(์ •๊ทœํ™”) -> ํžˆ์Šคํ† ๊ทธ๋žจ ๊ฒฝ๊ณ„๊ฐ’ ์„ค์ •(-1.0f ์—ญํˆฌ์˜, 0.12f ์ด์ง„ ์—ญํˆฌ์˜) -> ์—ญํˆฌ์˜ ์–ป๊ธฐ
[์ปฌ๋Ÿฌ] ROI -> ์ปฌ๋Ÿฌํžˆ์Šคํ† ๊ทธ๋žจ ๋นˆ ์„ค์ •(8) -> ์ปฌ๋Ÿฌํžˆ์Šคํ† ๊ทธ๋žจ ์ฐพ๊ธฐ -> ํžˆ์Šคํ† ๊ทธ๋žจ ์„ค์ •(์ •๊ทœํ™”) -> ํžˆ์Šคํ† ๊ทธ๋žจ ๊ฒฝ๊ณ„๊ฐ’ ์„ค์ •(0.05f) -> ์ปฌ๋Ÿฌ ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์—ญํˆฌ์˜ ์–ป๊ธฐ
[ab] ROI -> ์ปฌ๋Ÿฌํžˆ์Šคํ† ๊ทธ๋žจ ๋นˆ ์„ค์ •(256) -> ์ปฌ๋Ÿฌํžˆ์Šคํ† ๊ทธ๋žจ ์ฐพ๊ธฐ -> ํžˆ์Šคํ† ๊ทธ๋žจ ์„ค์ •(์ •๊ทœํ™”) -> ํžˆ์Šคํ† ๊ทธ๋žจ ๊ฒฝ๊ณ„๊ฐ’ ์„ค์ •(0.05f) -> BGR2Lab๊ณต๊ฐ„์œผ๋กœ ๋ณ€๊ฒฝ -> ์ฑ„๋„{1,2ab์„ ํƒ ํ›„} ์—ญํˆฌ์˜ ์–ป๊ธฐ
[Hue] ROI -> ์ปฌ๋Ÿฌํžˆ์Šคํ† ๊ทธ๋žจ ๋นˆ ์„ค์ •(180) -> ์ปฌ๋Ÿฌํžˆ์Šคํ† ๊ทธ๋žจ ์ฐพ๊ธฐ -> ํžˆ์Šคํ† ๊ทธ๋žจ ์„ค์ •(์ •๊ทœํ™”) -> ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ๊ฒฝ๊ณ„๊ฐ’ ์„ค์ •(0.05f) -> BGR2HSV๊ณต๊ฐ„์œผ๋กœ ๋ณ€๊ฒฝ -> ์ฑ„๋„ 0hue ์„ ํƒํ›„ ์—ญํˆฌ์˜ ์–ป๊ธฐ
ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์—ญํˆฌ์˜ ๊ฒฐ๊ณผ๋Š” ์ง€์ •ํ•œ ์˜์ƒ ์œ„์น˜์—์„œ ์˜์ƒ ๋‚ด์šฉ์˜ ํŠน์ • ์กฐ๊ฐ์„ ๋ฐœ๊ฒฌํ•  ํ™•๋ฅ ์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ™•๋ฅ  ๋งต์ด๋‹ค. ๊ฐ์ฒด์˜ ์ •ํ™•ํ•œ ์œ„์น˜๋ฅผ ์ฐพ์„ ๋•Œ ๋งค์šฐ ๊ฐ€๋Šฅ์„ฑ์ด ํฐ ์œ„์น˜๋Š” ์ง€์ •ํ•œ ์œˆ๋„์šฐ ๋‚ด๋ถ€์—์„œ ์ตœ๋Œ€ํ™”ํ•œ ํ™•๋ฅ ์ด๋‹ค.
* ์œˆ๋„์šฐ(Window)๋Š” ํ–‰๋ ฌ ํ˜•ํƒœ์˜ ํ™”์†Œ ๊ทธ๋ฃน์œผ๋กœ ์ดํ•ดํ•˜๋ฉด ๋˜๋ฉฐ, ๋งˆ์Šคํฌ(mask), ์ปค๋„(kernel)๋“ฑ์œผ๋กœ ํ‘œํ˜„ํ•˜๊ธฐ๋„ ํ•œ๋‹ค.
- ์ดˆ๊ธฐ ์œ„์น˜๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ ํ›„ ๋ฐ˜๋ณต์ ์œผ๋กœ ์›€์ง์ด๋ฉด์„œ ์ •ํ™•ํ•œ ๊ฐ์ฒด์˜ ์œ„์น˜๋ฅผ ์ฐพ์•„๋‚ด๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ‰๊ท  ์ด๋™ ์•Œ๊ณ ๋ฆฌ์ฆ˜(mean shift algorithm)์ด๋ผ๊ณ  ํ•œ๋‹ค.
1) ํ‰๊ท  ์ด๋™ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ cv::meanShiftํ•จ์ˆ˜๋กœ opencv2/video/tracking.hpp์•ˆ์— ๋“ค์–ด์žˆ๋‹ค.
ํ™•๋ฅ  ํ•จ์ˆ˜์˜ ์ง€์—ญ ์ตœ๋Œ€์น˜(local maxima)๊ฐ€ ์žˆ๋Š” ์œ„์น˜๋ฅผ ์ฐพ๋Š” ๋ฐ˜๋ณต ๊ณ„์‚ฐ๋ฒ•(iterative procedure)์ด๋‹ค. ๋ฏธ๋ฆฌ ์ •์˜๋œ ์œˆ๋„์šฐ ์•ˆ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์ ์˜ ์ค‘์‹ฌ(centroid)์ด๋‚˜ ๊ฐ€์ค‘ ํ‰๊ท (weighted mean)์„ ์ฐพ๋Š”๋ฐฉ์‹์œผ๋กœ
์ˆ˜ํ–‰ํ•œ๋‹ค. ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์œˆ๋„์šฐ ์ค‘์•™(window center)์„ ์ค‘์‹ฌ ์œ„์น˜๋กœ ์˜ฎ๊ธด ํ›„ ์œˆ๋„์šฐ์˜ ์ค‘์•™์ด ์•ˆ์ •์ (stable point)์œผ๋กœ ์ˆ˜๋ ดํ•  ๋•Œ๊นŒ์ง€ ํ•ด๋‹น ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•œ๋‹ค. OpenCV์˜ ๊ตฌํ˜„๋ถ€์—์„œ 2๊ฐœ์˜ ์ค‘์ง€๊ธฐ์ค€(stopping criteria)์„ ์ •์˜ํ•˜๋ฉฐ,
๋ฐ˜๋ณต ์ตœ๋Œ€ ํšŸ์ˆ˜(MAX_ITER), ๊ทธ๋ฆฌ๊ณ  ์•ˆ์ •์ ์— ์ˆ˜๋ ด๋˜๋„๋ก ๊ณ ๋ ค๋ผ์•ผ ํ•˜๋Š” ์œ„์น˜์˜ ์•„๋ž˜์ธ ์œˆ๋„์šฐ ์ค‘์•™ ๋ณ€์œ„ ๊ฐ’(EPS)์ด๋‹ค. 2๊ฐœ์˜ ์ค‘์ง€ ๊ธฐ์ค€์€ cv::TermCriteria์ธ์Šคํ„ด์Šค์— ์ €์žฅ๋œ๋‹ค. cv::meanShiftํ•จ์ˆ˜๋Š” ์ˆ˜ํ–‰ํ–ˆ๋˜ ๋ฐ˜๋ณตํšŸ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
ex)
//์ดˆ๊ธฐ ์œˆ๋„์šฐ ์œ„์น˜
cv::rectangle(image, rect, cv::Scalar(0, 0, 255));
//ํ‰๊ท  ์ด๋™์œผ๋กœ ๊ฐ์ฒด ํƒ์ƒ‰
cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS,
10, //์ตœ๋Œ€ 10ํšŒ ๋ฐ˜๋ณต
1); //๋˜๋Š” ์ค‘์‹ฌ ์œ„์น˜ ๋ณ€ํ™”๊ฐ€ 1ํ”ฝ์…€ ๋ฏธ๋งŒ์ด ๋  ๋•Œ๊นŒ์ง€
cout << "meanshift= " << cv::meanShift(result, rect, criteria) << endl;
//๊ฒฐ๊ณผ ์œˆ๋„์šฐ ๊ทธ๋ฆฌ๊ธฐ
cv::rectangle(image, rect, cv::Scalar(0, 255, 0));
2) OpenCV์—์„œ ์ƒ‰์ƒ ๊ฐ’์˜ ๋ฒ”์œ„๋Š” 0์—์„œ 180๊นŒ์ง€ ์ด๋ฏ€๋กœ(8๋น„ํŠธ) ์ด๋ฏ€๋กœ ์‹ค๋ฌด ํ˜„์žฅ์—์„œ HSV์ปฌ๋Ÿฌ ๊ณต๊ฐ„์„ ๋‹ค๋ฃฐ ๋•Œ ์–ด๋ ค์›€์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” 0~ 360์˜ ๋ฒ”์œ„๋ฅผ ๊ฐ€์ง€๋ฅผ ์ˆ˜ ์žˆ๋Š” ์‹ค์ˆ˜ํ˜•(32๋น„ํŠธ) ์˜์ƒ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜
cv::cvtColor ํ•จ์ˆ˜์™€ cv::ConvertScaleํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์ ์ ˆํžˆ ๊ตฌํ˜„ํ•œ๋‹ค. RGB ์ปฌ๋Ÿฌ๊ณต๊ฐ„์„ HSV์ปฌ๋Ÿฌ๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜ํ• ๋•Œ๋Š” RGB์ปฌ๋Ÿฌ์˜์ƒ์˜ ๊ฐ ์ฑ„๋„ ๋ฒ”์œ„๋ฅผ [0,1]๋กœ ๋ณ€ํ™˜ํ•˜๋Š” cv::ConvertScale๋ฅผ ํ˜ธ์ถœํ•œ ํ›„ cv::cvtColor๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.
๋ฐ˜๋Œ€๋Š” cv::cvtColor๋กœ ๋ณ€ํ™˜ํ•œ ํ›„ RGB์ปฌ๋Ÿฌ๊ณต๊ฐ„์˜ ๊ฐ ์ฑ„๋„์ด[0,255]๋ฒ”์œ„๋ฅผ ๊ฐ–๋„๋ก cv::ConvertScaleํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
3) OpenCV์˜ ํ‰๊ท  ์ด๋™ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ฐœ์„ ํ•œ ๋ฒ„์ „์ธ, ์œˆ๋„์šฐ ํฌ๊ธฐ์™€ ๋ฐฉํ–ฅ์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋Š” ์บ ์‹œํ”„ํŠธ(CamShift)์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์žˆ๋‹ค.
4) ๋‚ด์šฉ ๊ธฐ๋ฐ˜ ์˜์ƒ ๊ฒ€์ƒ‰(Content-based Image Retrieval:CBIR)์€ ์ปดํ“จํ„ฐ ๋น„์ „์—์„œ ์ค‘์š”ํ•œ ๋ฌธ์ œ์ด๋ฉฐ, ์ฃผ์–ด์ง„ ์งˆ์˜ ์˜์ƒ๊ณผ ๋น„์Šทํ•œ ๋‚ด์šฉ์ด ์กด์žฌํ•˜๋Š” ์˜์ƒ ์ง‘ํ•ฉ์„ ์ฐพ๋Š” ๊ณผ์ •์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋น„๊ตํ•จ์œผ๋กœ ์œ ์‚ฌ๋„๋ฅผ ์ธก์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ๋น„๊ต๋ฅผ ํ†ตํ•ด ๊ฒ€์ƒ‰ํ•˜๋Š” cv::compareHist()ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค. double ์ˆ˜์น˜๋กœ ๊ฒฐ๊ณผ๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ ๋น„์Šทํ•œ ์ •๋„๋ฅผ ์ˆ˜์น˜ํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.
ํ”Œ๋ž˜๊ทธ ์ข…๋ฅ˜๋Š” ๋” ๋‹ค์–‘ํ•˜์ง€๋งŒ ์ผ๋ถ€๋งŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜์ž๋ฉด
- HISTCMP_INTERSECT : ๊ฐ ํžˆ์Šคํ† ๊ทธ๋žจ์—์„œ ๊ฐ ๋นˆ๋งˆ๋‹ค ๋‘ ๊ฐ’์„ ๋‹จ์ˆœํ•˜๊ฒŒ ๋น„๊ตํ•œ ํ›„ ์ตœ์†Ÿ๊ฐ’์„ ์œ ์ง€ํ•œ๋‹ค. ์œ ์‚ฌ๋„ ์ธก์ •์€ ์ด๋Ÿฐ ์ตœ์†Ÿ๊ฐ’์˜ ํ•ฉ์ด ๋œ๋‹ค. ๋‘ ์˜์ƒ์ด ์ปฌ๋Ÿฌ๊ฐ€ ์—†๋Š” ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๊ฐ–๋Š”๋‹ค๋ฉด 0์ธ ์ธํ„ฐ์„น์…˜ ๊ฐ’์„ ์–ป๋Š” ๋ฐ˜๋ฉด, ๋‘ ํžˆ์Šคํ† ๊ทธ๋žจ์ด ๋™์ผํ•˜๋‹ค๋ฉด ํ™”์†Œ์˜ ์ด ๊ฐœ์ˆ˜์™€ ๊ฐ™์€ ๊ฐ’์„ ์–ป๋Š”๋‹ค.
- HISTCMP_CHISQR : ๋นˆ ๊ฐ„์˜ ์ •๊ทœํ™”๋œ ์ œ๊ณฑ ์ฐจ๋ฅผ ํ•ฉํ•˜๋Š” ์นด์ด ์ œ๊ณฑ(Chi-Square)์ธก์ •
- HISTCMP_CORREL : ์‹ ํ˜ธ์ฒ˜๋ฆฌ์—์„œ ๋‘ ์‹ ํ˜ธ ๊ฐ„์˜ ์œ ์‚ฌ๋„๋ฅผ ์ธก์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์ •๊ทœํ™”๋œ ์ƒํ˜ธ ์ƒ๊ด€ ์—ฐ์‚ฐ์ž์— ๊ธฐ๋ฐ˜์„ ๋‘๊ณ  ์žˆ๋Š” ์ƒ๊ด€๊ด€๊ณ„(Corrleation) ๋ฐฉ๋ฒ•
- HISTCMP_BHATTACHARYYA : ํ†ต๊ณ„์—์„œ ๋‘ ํ™•๋ฅ  ๋ถ„ํฌ ๊ฐ„์˜ ์œ ์‚ฌ๋„๋ฅผ ์ถ”์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ฐ”ํƒ€์ฐจ๋ฅด์•ผ(Bhattacharyya) ์ธก์ •์ด ์žˆ๋‹ค.
5) ์ ๋ถ„ ์˜์ƒ์œผ๋กœ ํ™”์†Œ๊ฐœ์ˆ˜ ์„ธ๊ธฐ - ์˜์ƒ ๋ถ€๋ถ„ ์˜์—ญ์— ๊ฑธ์นœ ํ™”์†Œ๋ฅผ ์…€ ๋•Œ์˜ ํšจ์œจ์„ฑ์„ ๊ทน์ ์œผ๋กœ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๋กœ๋Š” ์ ๋ถ„ ์˜์ƒ(Integral Image)์„ ๋“ค ์ˆ˜ ์žˆ๋‹ค.
์—ฌ๋Ÿฌํฌ๊ธฐ์˜ ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ(Sliding Window)๋ฅผ ๊ฐ–๊ณ  ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ์„ ํฌํ•จํ•œ ์‘์šฉ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค.
* ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ๋ž€ ์˜์ƒ์—์„œ ๊ฐ์ฒด๋ฅผ ์ฐพ๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•์ด๋ฉฐ, ์˜์ƒ ์•ˆ์—์„œ ์œˆ๋„์šฐ๋ฅผ ์ผ์ •ํ•œ ๊ฐ„๊ฒฉ์œผ๋กœ ์ด๋™์‹œํ‚ค๋ฉด์„œ ์œˆ๋„์šฐ ๋‚ด์šฉ์„ ๊ธฐ์ค€์œผ๋กœ ์ฐพ์œผ๋ ค๋Š” ๊ฐ์ฒด์ธ์ง€์˜ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ ์—ฌ๋Ÿฌํฌ๊ธฐ๋ž€ ๋‹ค์–‘ํ•œ ํฌ๊ธฐ์˜ ์˜์ƒ(์ €ํ•ด์ƒ-๊ณ ํ•ด์ƒ) ์˜์ƒ ํ”ผ๋ผ๋ฏธ๋“œ๋ฅผ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
์ด๋•Œ ๊ฐ์ฒด์˜ ํฌ๊ธฐ์™€ ์œ„์น˜๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์˜์ƒ ํ”ผ๋ผ๋ฏธ๋“œ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฐพ์œผ๋ ค๋Š” ๊ฐ์ฒด๊ฐ€ ์žˆ๋Š”์ง€ ๋ฐ˜๋ณต์ ์œผ๋กœ ์กฐ์‚ฌํ•œ๋‹ค. ์ด๋กœ ์ธํ•ด ์ฒ˜๋ฆฌ ์†๋„๊ฐ€ ์ €ํ•˜๋œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. ์ด๊ฒƒ์„ ๊ฐœ์„ ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ค‘์—์„œ ๋ฐ˜๋ณต๊ณผ์ •์„ ์ตœ์†Œํ™”ํ•œ ESS(Efficient Subwindow Search)๋ฐฉ๋ฒ•์„ ๋“ค ์ˆ˜ ์žˆ๋‹ค.
์—ฌ๋Ÿฌ ์˜์ƒ ์˜์—ญ์— ๊ฑธ์นœ ํ™”์†Œ๋ฅผ ํ•ฉํ•ด์•ผ ํ•  ๋•Œ๋Š” ์ ๋ถ„ ์˜์ƒ์ด ์œ ์šฉํ•˜๋‹ค.
* ์ ๋ถ„ ์˜์ƒ์€ ํžˆ์Šคํ† ๊ทธ๋žจ์„ ์ด์šฉํ•ด ์‹œ๊ฐ์  ์ถ”์ ์„ ํ• ๋•Œ๋„ ์œ ์šฉํ•˜๋‹ค. ์ฝ”๋“œ์—์„œ ๊ฐ€์žฅ ๋น ๋ฅธ ์†๋„๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.
๊ณผ์ •: ์› ์˜์ƒ์—์„œ ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ > ์› ์˜์ƒ ์ž‘์€ ๊ฐฏ์ˆ˜ bin์˜ ํžˆ์Šคํ† ๊ทธ๋žจ ์ œ์ž‘ > ์› ์˜์ƒ ์ด์ง„ ํ‰๋ฉด์œผ๋กœ ๊ตฌ์„ฑ๋œ ๋‹ค์ฑ„๋„ ์˜์ƒ์œผ๋กœ ๋ณ€ํ™˜ > ์› ์˜์ƒ ์ ๋ถ„ ์˜์ƒ ๊ณ„์‚ฐ > ์ฐพ๋Š” ์˜์ƒ ๊ฐ™์€ ์ˆ˜์˜ bin์˜ ํžˆ์Šคํ† ๊ทธ๋žจ ์ƒ์„ฑ > ์ฐพ๋Š” ์˜์ƒ ์ด์ง„ ํ‰๋ฉด์˜์ƒ ์ƒ์„ฑ >
์ฐพ๋Š”์˜์ƒ ์ ๋ถ„์˜์ƒ ๊ณ„์‚ฐํ•˜๊ธฐ > (๋ฒ”์œ„๋ฅผ ์ค„ ๊ฑฐ๋ฉด ์ˆ˜ํ‰์ธ ๊ธด ์กฐ๊ฐ ์ˆœํšŒํ•˜๋ฉด์„œ) ์ฐพ๋Š” ์ ๋ถ„์˜์ƒ์—์„œ ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ > ๋งจ ์ฒ˜์Œ์— ๊ณ„์‚ฐ ๋œ ๊ธฐ์ค€ ํžˆ์Šคํ† ๊ทธ๋žจ๊ณผ ์ฐพ๋Š” ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ ๋œ ๊ฒƒ์„ ์‚ฌ์šฉํ•ด ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ > ๊ฐ€์žฅ ๋น„์Šทํ•œ ํžˆ์Šคํ† ๊ทธ๋žจ ์œ„์น˜ ์ฐพ์•„์„œ ๊ทธ ์ ์„ ๊ธฐ์ค€์œผ๋กœ ๋„ค๋ชจ ์น˜๋ฉด ์ฐพ๋Š” ๊ฒƒ
6) ์ ์‘์  ๊ฒฝ๊ณ„ํ™” - ๊ณ ์ •๋œ ๊ฒฝ๊ณ„ํ™”๋Š” ์Œ์˜์•„๋ž˜ ์žˆ๋Š” ํ…์ŠคํŠธ๋Š” ๋ณด์ด์ง€ ์•Š์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ์œ„ํ•ด ๊ฐ ํ™”์†Œ์˜ ์ด์›ƒ์œผ๋กœ ๊ณ„์‚ฐํ•˜๋Š” ์ง€์—ญ ๊ฒฝ๊ณ„ํ™”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ํ™”์†Œ๊ฐ€ ์ง€์—ญ ํ‰๊ท  ๊ฐ’๊ณผ ๋‘๋“œ๋Ÿฌ์ง€๊ฒŒ ์ฐจ์ด๊ฐ€ ๋‚œ๋‹ค๋ฉด ์ด์ƒ์น˜๋กœ ๊ฐ„์ฃผํ•œ ํ›„, ๊ฒฝ๊ณ„ํ™” ๊ณผ์ •์—์„œ ์ž˜๋ผ๋‚ธ๋‹ค.
๊ทธ๋กœ ์ธํ•ด ์ ์‘์  ๊ฒฝ๊ณ„ํ™”์—์„œ๋Š” ๋ชจ๋“  ํ™”์†Œ ์ฃผ๋ณ€์˜ ์ง€์—ญ ํ‰๊ท  ๊ณ„์‚ฐ์ด ํ•„์š”ํ•˜๋‹ค. ์ ๋ถ„ ์˜์ƒ์„ ์ด์šฉํ•˜๋ฉด ํ•„์š”ํ•œ ์—ฌ๋Ÿฌ ์˜์ƒ์˜ ์œˆ๋„์šฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ํ•ฉ์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๊ฒƒ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์œผ๋ก  adaptiveThreshold()ํ•จ์ˆ˜๋ฅผ ์“ฐ๊ฑฐ๋‚˜ ์ง์ ‘ ์ ๋ถ„๊ณ„์‚ฐ์œผ๋กœ ํ•˜๊ฑฐ๋‚˜ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.
<์ฝ”๋“œ 1 - ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include "histogram.h"
using namespace std;
int main()
{
cv::Mat image = cv::imread("../images/group.jpg", 0);
if (image.empty()) return 0;
cv::namedWindow("Image");
cv::imshow("Image", image);
//ํžˆ์Šคํ† ๊ทธ๋žจ ๊ฐ์ฒด
Histogram1D h;
//ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
cv::Mat histo = h.getHistogram(image);
//๊ฐ ๋นˆ์„ ์ˆœํšŒ
for (int i = 0; i < 256; i++)
cout << "Value" << i << " = " << histo.at<float>(i) << endl;
//ํžˆ์Šคํ† ๊ทธ๋žจ์„ ์˜์ƒ์œผ๋กœ ํ‘œ์‹œ
cv::namedWindow("Histogram");
cv::imshow("Histogram", h.getHistogramImage(image));
//ํžˆ์Šคํ† ๊ทธ๋žจ๊ณผ ์„ ํƒ๋œ ๊ฒฝ๊ณ„๊ฐ’์œผ๋กœ ์žฌํ‘œ์‹œ
cv::Mat hi = h.getHistogramImage(image);
cv::line(hi, cv::Point(70, 0), cv::Point(70, 255), cv::Scalar(128));
cv::namedWindow("Histogram with threshold value");
cv::imshow("Histogram with threshold value", hi);
//๊ณจ ๋ถ€๋ถ„์— ๊ฒฝ๊ณ„ํ™”ํ•˜์—ฌ ์ด์ง„ ์˜์ƒ ์ƒ์„ฑํ•˜๊ธฐ
cv::Mat thresholded; //๊ฒฐ๊ณผ ์ด์ง„์˜์ƒ
cv::threshold(image, thresholded,
70, //๊ฒฝ๊ณ„ ๊ฐ’
255, //๊ฒฝ๊ณ„ ๊ฐ’์„ ์ดˆ๊ณผํ•˜๋Š” ํ”ฝ์…€์— ํ• ๋‹น ๋œ ๊ฐ’
cv::THRESH_BINARY);
//๊ฒฝ๊ณ„ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Binary Image");
cv::imshow("Binary Image", thresholded);
//ํ‰ํ™œํ™” ์˜์ƒ
cv::Mat eq = h.equalize(image);
//ํ‰ํ™œํ™” ๊ฒฐ๊ณผ ์˜์ƒ
cv::namedWindow("Equalized Image");
cv::imshow("Equalized Image", eq);
//ํ‰ํ™œํ™” ์˜์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ
cv::namedWindow("Equalized H");
cv::imshow("Equalized H", h.getHistogramImage(eq));
//๋ฐฑ๋ถ„์œ„์ˆ˜ 1%์— ๊ฐ๊ฐ ํžŒ์ƒ‰๊ณผ ๋ฐฑ์ƒ‰์œผ๋กœ ์„ธํŒ…ํ•ด ๋Š˜๋ฆฐ ์˜์ƒ
cv::Mat str = h.stretch(image, 0.01f);
//๋Š˜๋ฆฐ ๊ฒฐ๊ณผ ์˜์ƒ
cv::namedWindow("Stretched Image");
cv::imshow("Stretched Image", str);
//๋Š˜๋ฆฐ ์˜์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ
cv::namedWindow("Stretched H");
cv::imshow("Stretched H", h.getHistogramImage(str));
//์ตœ์†Œ๊ฐ’ 80๊ฐœ์˜ ๋นˆ์ˆ˜๋ฅผ ์ •ํ•ด ๊ฐ๊ฐ ํžŒ์ƒ‰๊ณผ ๋ฐฑ์ƒ‰์œผ๋กœ ์„ธํŒ…ํ•ด ๋Š˜๋ฆฐ ์˜์ƒ
cv::Mat str2 = h.stretch(image, 80);
//๋Š˜๋ฆฐ ๊ฒฐ๊ณผ ์˜์ƒ 2
cv::namedWindow("Stretched Image 2");
cv::imshow("Stretched Image 2", str2);
//๋Š˜๋ฆฐ ์˜์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ 2
cv::namedWindow("Stretched H 2");
cv::imshow("Stretched H 2", h.getHistogramImage(str2));
//์˜์ƒ ๋ฐ˜์ „ ํ…Œ์ด๋ธ” ์ƒ์„ฑ
cv::Mat lut(1, 256, CV_8U); // 1x256 ํ–‰๋ ฌ
//Or
//int dim(256);
//cv::Mat lut(1, //1์ฐจ์›
// &dim, //256ํ•ญ๋ชฉ
// uhcar); //uchar
for (int i = 0; i < 256; i++)
{
//0์€ 255๊ฐ€ ๋˜๊ณ , 1์€ 254๊ฐ€ ๋˜๋Š” ๋“ฑ์˜ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ
lut.at<uchar>(i) = 255 - i;
}
//๋ฃฉ์—… ํ…Œ์ด๋ธ” ์ ์šฉํ•œ ์—ญ์ƒ ํ‘œ์‹œํ•˜๊ธฐ
cv::Mat luxR = h.applyLookUp(image, lut);
//๋ฃฉ์—… ํ…Œ์ด๋ธ” ์ ์šฉํ•œ ์—ญ์ƒ ํ‘œ์‹œํ•˜๊ธฐ
cv::Mat luxR2 = h.applyLookUpWithIterator(image, lut);
//์—ญ์ƒ(Negative) ์˜์ƒ
cv::namedWindow("Negative Image");
cv::imshow("Negative Image", luxR);
//์—ญ์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ
cv::namedWindow("Negative H");
cv::imshow("Negative H", h.getHistogramImage(luxR));
//์—ญ์ƒ(Negative) ์˜์ƒ 2
cv::namedWindow("Negative Image 2");
cv::imshow("Negative Image 2", luxR2);
//์—ญ์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ 2
cv::namedWindow("Negative H 2");
cv::imshow("Negative H 2", h.getHistogramImage(luxR2));
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 2 - ํŠน์ • ์˜์ƒ ๋‚ด์šฉ์„ ๊ฒ€์ถœํ•˜๊ธฐ ์œ„ํ•œ ํžˆ์Šคํ† ๊ทธ๋žจ >
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include "histogram.h"
#include "contentFinder.h"
#include "colorhistogram.h"
using namespace std;
int main()
{
//์ž…๋ ฅ ์˜์ƒ ์ฝ์–ด์˜ค๊ธฐ
cv::Mat image = cv::imread("../images/waves.jpg", 0);
if (!image.data)
return 0;
//ROI ์˜์ƒ ์ •์˜ํ•˜๊ธฐ
cv::Mat imageROI;
imageROI = image(cv::Rect(216, 33, 24, 30)); //๊ตฌ๋ฆ„ ์˜์—ญ
//์ฐธ์กฐ ์˜์—ญ ํ‘œ์‹œ
cv::namedWindow("Reference");
cv::imshow("Reference", imageROI);
//์ฐธ์กฐ ์˜์—ญ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ ์ฐพ๊ธฐ
Histogram1D h;
cv::Mat hist = h.getHistogram(imageROI);
cv::namedWindow("Reference Hist");
cv::imshow("Reference Hist", h.getHistogramImage(imageROI));
//ContentFinder ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
ContentFinder finder;
//ํžˆ์Šคํ† ๊ทธ๋žจ ์—ญํˆฌ์˜์œผ๋กœ ์„ค์ •
finder.setHistogram(hist);
finder.setThreshold(-1.0f);
//์—ญํˆฌ์˜ ์–ป๊ธฐ
cv::Mat result1;
result1 = finder.find(image);
//๋ฐ˜์ „์˜์ƒ ๊ณผ ๊ฒฐ๊ณผํ™”๋ฉด ์ƒ์„ฑ
cv::Mat tmp;
result1.convertTo(tmp, CV_8U, -1.0, 255.0);
cv::namedWindow("Backprojection Result");
cv::imshow("Backprojection Result", tmp);
//์ด์ง„ ์—ญํˆฌ์˜ ์–ป๊ธฐ
finder.setThreshold(0.12f);
result1 = finder.find(image);
//์ฐธ์กฐ์˜์—ญ์— ์‚ฌ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ
cv::rectangle(image, cv::Rect(216, 33, 24, 30), cv::Scalar(0, 0, 0));
//์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Image");
cv::imshow("Image", image);
//๊ฒฐ๊ณผ ํ‘œ์‹œ
cv::namedWindow("Detection Result");
cv::imshow("Detection Result", result1);
//์ปฌ๋Ÿฌ ์˜์ƒ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
ColorHistogram hc;
cv::Mat color = cv::imread("../images/waves.jpg");
//๊ด€์‹ฌ์˜์—ญ ์ถ”์ถœ
imageROI = color(cv::Rect(0, 0, 100, 45)); //ํ‘ธ๋ฅธ ํ•˜๋Š˜ ์˜์—ญ
//3D ์ปฌ๋Ÿฌ ํžˆ์Šคํ† ๊ทธ๋žจ ์–ป๊ธฐ(์ฑ„๋„๋‹น 8๊ฐœ์˜ ๋นˆ)
hc.setSize(8); //8*8*8
cv::Mat shist = hc.getHistogram(imageROI);
//์—ญํˆฌ์˜ํ•  ํžˆ์Šคํ† ๊ทธ๋žจ ์„ค์ •
finder.setHistogram(shist);
finder.setThreshold(0.05f);
//์ปฌ๋Ÿฌ ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์—ญํˆฌ์˜ ์–ป๊ธฐ
result1 = finder.find(color);
cv::namedWindow("Color Detection Result");
cv::imshow("Color Detection Result", result1);
//๋‘ ๋ฒˆ์งธ ์ปฌ๋Ÿฌ ์˜์ƒ
cv::Mat color2 = cv::imread("../images/dog.jpg");
cv::namedWindow("Second Image");
cv::imshow("Second Image", color2);
//์ปฌ๋Ÿฌ ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์—ญํˆฌ์˜ ์–ป๊ธฐ
cv::Mat result2 = finder.find(color2);
cv::namedWindow("Result Color 2");
cv::imshow("Result Color 2", result2);
//ab ์ปฌ๋Ÿฌ ํžˆ์Šคํ† ๊ทธ๋žจ ์–ป๊ธฐ
hc.setSize(256); //256*256
cv::Mat colorhist = hc.getabHistogram(imageROI);
//2D ํžˆ์Šคํ† ๊ทธ๋žจ ํ‘œ์‹œํ•˜๊ธฐ
colorhist.convertTo(tmp, CV_8U, -1.0, 255.0);
cv::namedWindow("ab histogram");
cv::imshow("ab histogram", tmp);
//์—ญํˆฌ์˜ํ•  ํžˆ์Šคํ† ๊ทธ๋žจ ์„ค์ •
finder.setHistogram(colorhist);
finder.setThreshold(0.05f);
//Lab ๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ
cv::Mat lab;
cv::cvtColor(color, lab, CV_BGR2Lab);
//ab ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์—ญํˆฌ์˜ ์–ป๊ธฐ
int ch[2] = { 1, 2 };
result1 = finder.find(lab, 0, 256.0f, ch);
cv::namedWindow("Result ab 1");
cv::imshow("Result ab 1",result1);
//๋‘ ๋ฒˆ์งธ ์ปฌ๋Ÿฌ ์˜์ƒ
cv::cvtColor(color2, lab, CV_BGR2Lab);
//ab ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์—ญํˆฌ์˜ ์–ป๊ธฐ
result2 = finder.find(lab, 0, 256.0, ch);
cv::namedWindow("Result ab 2");
cv::imshow("Result ab 2", result2);
//ํ•˜๋Š˜ ์ฐธ์กฐ์˜์—ญ์— ์‚ฌ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ
cv::rectangle(color, cv::Rect(0, 0, 100, 45), cv::Scalar(0, 0, 0));
cv::namedWindow("Color Image");
cv::imshow("Color Image", color);
//์ƒ‰์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ ์–ป๊ธฐ
hc.setSize(180); //180๊ฐœ์˜ ๋นˆ
colorhist = hc.getHueHistogram(imageROI);
//์—ญํˆฌ์˜ํ•  ํžˆ์Šคํ† ๊ทธ๋žจ ์„ค์ •
finder.setHistogram(colorhist);
//HSV๋กœ ๋ณ€ํ™˜
cv::Mat hsv;
cv::cvtColor(color, hsv, CV_BGR2HSV);
//์ƒ‰ ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์—ญํˆฌ์˜
ch[0] = 0;
result1 = finder.find(hsv, 0.0f, 180.0f, ch);
cv::namedWindow("Result Hue 1");
cv::imshow("Result Hue 1", result1);
//๋‘ ๋ฒˆ์งธ ์ปฌ๋Ÿฌ ์˜์ƒ
color2 = cv::imread("../images/dog.jpg");
//HSV ๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜
cv::cvtColor(color2, hsv, CV_BGR2HSV);
//์ƒ‰์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์—ญ๋ณ€ํ™˜ ์–ป๊ธฐ
result2 = finder.find(hsv, 0.0f, 180.0f, ch);
cv::namedWindow("Result Hue 2");
cv::imshow("Result Hue 2", result2);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 3 - ๊ฐ์ฒด๋ฅผ ์ฐพ๋Š” ํ‰๊ท  ์ด๋™ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‚ฌ์šฉ>
#include <iostream>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/video/tracking.hpp>
#include "contentFinder.h"
#include "colorhistogram.h"
using namespace std;
int main()
{
//๊ธฐ์ค€ ์˜์ƒ ์ฝ๊ธฐ
cv::Mat image = cv::imread("../images/baboon01.jpg");
if (!image.data) return 0;
//์ดˆ๊ธฐ ์œˆ๋„์šฐ ์œ„์น˜
cv::Rect rect(110, 45, 35, 45);
cv::rectangle(image, rect, cv::Scalar(0, 0, 255));
//๊ฐœ์ฝ” ์›์ˆญ์ด์˜ ์–ผ๊ตด ROI
cv::Mat imageROI = image(rect);
cv::namedWindow("Image 1");
cv::imshow("Image 1", image);
//๊ฐœ์ฝ” ์›์ˆญ์ด ์–ผ๊ตด์˜ ์ƒ‰์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ ์–ป๊ธฐ
int minSat = 65;
ColorHistogram hc;
cv::Mat colorhist = hc.getHueHistogram(imageROI, minSat);
ContentFinder finder;
finder.setHistogram(colorhist);
finder.setThreshold(0.2f);
//HSV๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜ (๊ทธ๋ƒฅ ํ‘œ์‹œ ์šฉ์œผ๋กœ)
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
//3์ฑ„๋„์„ 3๊ฐœ์˜ ์˜์ƒ์œผ๋กœ ๋ถ„๋ฆฌ
vector<cv::Mat> v;
cv::split(hsv, v);
//๋‚ฎ์€ ์ฑ„๋„๋ฅผ ๊ฐ–๋Š” ํ™”์†Œ๋ฅผ ์ œ์™ธ
cv::threshold(v[1], v[1], minSat, 255, cv::THRESH_BINARY);
cv::namedWindow("Saturation Mask");
cv::imshow("Saturation Mask", v[1]);
//๋‘ ๋ฒˆ์จฐ ์˜์ƒ
image = cv::imread("../images/baboon02.jpg");
cv::namedWindow("Image 2");
cv::imshow("Image 2", image);
//HSV๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜
cv::cvtColor(image, hsv, CV_BGR2HSV);
//์ƒ‰์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ์„ ์—ญํˆฌ์˜ํ•œ ๊ฒฐ๊ณผ ์–ป๊ธฐ
int ch[1] = { 0 };
finder.setThreshold(-1.0f); //๊ฒฝ๊ณ„ํ™”ํ•˜์ง€ ์•Š์Œ
cv::Mat result = finder.find(hsv, 0.0f, 180.0f, ch);
//์—ญํˆฌ์˜ํ•œ ๊ฒฐ๊ณผ ํ‘œ์‹œ
cv::namedWindow("Backprojection on Second Image");
cv::imshow("Backprojection on Second Image", result);
//์ดˆ๊ธฐ ์œˆ๋„์šฐ ์œ„์น˜
cv::rectangle(image, rect, cv::Scalar(0, 0, 255));
//ํ‰๊ท  ์ด๋™์œผ๋กœ ๊ฐ์ฒด ํƒ์ƒ‰
cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS,
10, //์ตœ๋Œ€ 10ํšŒ ๋ฐ˜๋ณต
1); //๋˜๋Š” ์ค‘์‹ฌ ์œ„์น˜ ๋ณ€ํ™”๊ฐ€ 1ํ”ฝ์…€ ๋ฏธ๋งŒ์ด ๋  ๋•Œ๊นŒ์ง€
cout << "meanshift= " << cv::meanShift(result, rect, criteria) << endl;
//๊ฒฐ๊ณผ ์œˆ๋„์šฐ ๊ทธ๋ฆฌ๊ธฐ
cv::rectangle(image, rect, cv::Scalar(0, 255, 0));
//์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Image 2 Result");
cv::imshow("Image 2 Result", image);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 4 - ํžˆ์Šคํ† ๊ทธ๋žจ ๋น„๊ต๋ฅผ ์ด์šฉํ•œ ์œ ์‚ฌ ์˜์ƒ ๊ฒ€์ƒ‰>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include "imageComparator.h"
using namespace std;
int main()
{
//๊ธฐ์ค€ ์˜์ƒ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
cv::Mat image = cv::imread("../images/waves.jpg");
if (!image.data) return 0;
//์˜์ƒ ํ‘œ์‹œํ•˜๊ธฐ
cv::namedWindow("Query Image");
cv::imshow("Query Image", image);
ImageComparator c;
c.setReferenceImage(image);
//์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ๊ธฐ์ค€ ์˜์ƒ๊ณผ ๋น„๊ตํ•˜๊ธฐ
cv::Mat input = cv::imread("../images/dog.jpg");
cout << "waves vs dog: " << c.compare(input) << endl;
cv::namedWindow("dog");
cv::imshow("dog", input);
//์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ๊ธฐ์ค€ ์˜์ƒ๊ณผ ๋น„๊ตํ•˜๊ธฐ
input = cv::imread("../images/marais.jpg");
cout << "waves vs marais: " << c.compare(input) << endl;
cv::namedWindow("marais");
cv::imshow("marais", input);
//์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ๊ธฐ์ค€ ์˜์ƒ๊ณผ ๋น„๊ตํ•˜๊ธฐ
input = cv::imread("../images/bear.jpg");
cout << "waves vs bear: " << c.compare(input) << endl;
cv::namedWindow("bear");
cv::imshow("bear", input);
//์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ๊ธฐ์ค€ ์˜์ƒ๊ณผ ๋น„๊ตํ•˜๊ธฐ
input = cv::imread("../images/beach.jpg");
cout << "waves vs beach: " << c.compare(input) << endl;
cv::namedWindow("beach");
cv::imshow("beach", input);
//์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ๊ธฐ์ค€ ์˜์ƒ๊ณผ ๋น„๊ตํ•˜๊ธฐ
input = cv::imread("../images/polar.jpg");
cout << "waves vs polar: " << c.compare(input) << endl;
cv::namedWindow("polar");
cv::imshow("polar", input);
//์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ๊ธฐ์ค€ ์˜์ƒ๊ณผ ๋น„๊ตํ•˜๊ธฐ
input = cv::imread("../images/moose.jpg");
cout << "waves vs moose: " << c.compare(input) << endl;
cv::namedWindow("moose");
cv::imshow("moose", input);
//์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ๊ธฐ์ค€ ์˜์ƒ๊ณผ ๋น„๊ตํ•˜๊ธฐ
input = cv::imread("../images/lake.jpg");
cout << "waves vs lake: " << c.compare(input) << endl;
cv::namedWindow("lake");
cv::imshow("lake", input);
//์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ๊ธฐ์ค€ ์˜์ƒ๊ณผ ๋น„๊ตํ•˜๊ธฐ
input = cv::imread("../images/fundy.jpg");
cout << "waves vs fundy: " << c.compare(input) << endl;
cv::namedWindow("fundy");
cv::imshow("fundy", input);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 5 - ์ ๋ถ„ ์˜์ƒ์„ ์‚ฌ์šฉํ•˜์—ฌ ์œ ์‚ฌ ๊ฐ์ฒด ํƒ์ƒ‰ํ•˜๊ธฐ>
#include <iostream>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include "histogram.h"
#include "integral.h"
using namespace std;
int main()
{
//์˜์ƒ์—ด๊ธฐ
cv::Mat image = cv::imread("../images/bike55.bmp", 0);
if (!image.data) return 0;
//์˜์ƒ ROI ์ •์˜(์—ฌ๊ธฐ์„œ๋Š” ์ž์ „๊ฑฐ๋ฅผ ํƒ„ ์—ฌ์ž ์–ด๋ฆฐ์ด)
int xo = 97, yo = 112;
int width = 25, height = 30;
cv::Mat roi(image, cv::Rect(xo, yo, width, height));
//ํ•ฉ ๊ณ„์‚ฐ
//๋‹ค์ฑ„๋„ ์˜์ƒ์— ์ ์šฉํ•˜๋Š” ์Šค์นผ๋ผ ๋ฐ˜ํ™˜
cv::Scalar sum = cv::sum(roi);
cout << sum[0] << endl;
//์ ๋ถ„ ์˜์ƒ ๊ณ„์‚ฐ
cv::Mat integralImage;
cv::integral(image, integralImage, CV_32S);
//3๊ฐœ์˜ ๋ง์…ˆ/๋บ„์…ˆ์„ ์‚ฌ์šฉํ•ด ์˜์—ญ์— ๊ฑธ์นœ ํ•ฉ์„ ์–ป๊ธฐ
int sumInt = integralImage.at<int>(yo + height, xo + width) - integralImage.at<int>(yo + height, xo) - integralImage.at<int>(yo, xo + width) + integralImage.at<int>(yo, xo);
cout << sumInt << endl;
//16๊ฐœ ๋นˆ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ
Histogram1D h;
h.setNBins(16);
//ROI ์˜์ƒ์— ๋Œ€ํ•œ ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐํ•˜๊ธฐ
cv::Mat refHistogram = h.getHistogram(roi);
cv::namedWindow("Reference Histogram");
cv::imshow("Reference Histogram", h.getHistogramImage(roi, 16));
cout << refHistogram << endl;
//๋จผ์ € ์ด์ง„ 16ํ‰๋ฉด์˜์ƒ ์ƒ์„ฑํ•˜๊ธฐ
cv::Mat planes;
convertToBinaryPlanes(image, planes, 16);
//๊ทธ ํ›„ ์ ๋ถ„์˜์ƒ ๊ณ„์‚ฐํ•˜๊ธฐ
IntegralImage<float, 16> intHisto(planes);
//์ ๋ถ„์˜์ƒ๊ณผ 16๊ฐœ์˜ ๋นˆ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ ํ…Œ์ŠคํŒ…
cv::Vec<float, 16> histogram = intHisto(xo, yo, width, height);
std::cout << histogram << std::endl;
cv::namedWindow("Reference Histogram (2)");
cv::Mat im = h.getImageOfHistogram(cv::Mat(histogram), 16);
cv::imshow("Reference Histogram (2)", im);
//๋‘ ๋ฒˆ์งธ ์˜์ƒ ์ฐพ๊ธฐ
cv::Mat secondImage = cv::imread("../images/bike65.bmp", 0);
if (!secondImage.data) return 0;
//๋จผ์ € ์ด์ง„ 16ํ‰๋ฉด์˜์ƒ ์ƒ์„ฑํ•˜๊ธฐ
convertToBinaryPlanes(secondImage, planes, 16);
//๊ทธ ํ›„ ์ ๋ถ„์˜์ƒ ๊ณ„์‚ฐํ•˜๊ธฐ
IntegralImage<float, 16> intHistogram(planes);
//์ ๋ถ„์˜์ƒ๊ณผ 16๊ฐœ์˜ ๋นˆ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ ํ…Œ์ŠคํŒ…
histogram = intHistogram(135, 114, width, height);
std::cout << histogram << std::endl;
cv::namedWindow("Current Histogram");
cv::Mat im2 = h.getImageOfHistogram(cv::Mat(histogram), 16);
cv::imshow("Current Histogram", im2);
std::cout << "Distance= " << cv::compareHist(refHistogram, histogram, cv::HISTCMP_INTERSECT) << std::endl;
double maxSimilarity = 0.0;
int xbest, ybest;
//์ดˆ๊ธฐ ์˜์ƒ์— ์žˆ๋Š” ์—ฌ์ž ์–ด๋ฆฐ์ด ์œ„์น˜ ์ฃผ๋ณ€์˜ ์ˆ˜ํ‰์ธ ๊ธด ์กฐ๊ฐ ์ˆœํšŒ
for (int y = 110; y < 120; y++)
{
for (int x = 0; x < secondImage.cols - width; x++)
{
//์ ๋ถ„ ์˜์ƒ์„ ์ด์šฉํ•ด 16๊ฐœ ๋นˆ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
histogram = intHistogram(x, y, width, height);
//๊ธฐ์ค€ ํžˆ์Šคํ† ๊ทธ๋žจ๊ณผ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ
double distance = cv::compareHist(refHistogram, histogram, CV_COMP_INTERSECT);
//๋งค์šฐ ๋น„์Šทํ•œ ํžˆ์Šคํ† ๊ทธ๋žจ ์œ„์น˜ ์ฐพ๊ธฐ
if (distance > maxSimilarity)
{
xbest = x;
ybest = y;
maxSimilarity = distance;
}
//std::cout << "Distance(" << x << ", " << y << ")=" << distance << std::endl;
}
}
std::cout << "Best soluction= (" << xbest << ", " << ybest << ")=" << maxSimilarity << std::endl;
//ํƒ€๊ฒŸ ์˜ค๋ธŒ์ ํŠธ์— ์‚ฌ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ
cv::rectangle(image, cv::Rect(xo, yo, width, height), 0);
cv::namedWindow("Initial Image");
cv::imshow("Initial Image", image);
cv::namedWindow("New Image");
cv::imshow("New Image", secondImage);
//์ตœ์  ์œ„์น˜์—์„œ ์‚ฌ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ
cv::rectangle(secondImage, cv::Rect(xbest, ybest, width, height), 0);
//ํƒ์ƒ‰ ์˜์—ญ์— ์‚ฌ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ
cv::rectangle(secondImage, cv::Rect(0, 110, secondImage.cols, height + 10), 255);
cv::namedWindow("Object location");
cv::imshow("Object location", secondImage);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 6 - ์ ๋ถ„ ์˜์ƒ๊ณผ ์ ์‘์  ๊ฒฝ๊ณ„ํ™”>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include "integral.h"
int main()
{
cv::Mat image = cv::imread("../images/book.jpg", 0);
if (!image.data) return 0;
//์‰ฝ๊ฒŒ ๋ณด๊ธฐ์œ„ํ•ด ์˜์ƒ ํšŒ์ „ (-90, 270๋„ ๊ฐ™์€ ๊ฒƒ)
cv::transpose(image, image);
cv::flip(image, image, 0);
//์›๋ณธ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Original Image");
cv::imshow("Original Image", image);
//๊ณ ์ •๋œ ๊ฒฝ๊ณ„๊ฐ’ ์‚ฌ์šฉ
cv::Mat binaryFixed;
cv::Mat binaryAdaptive;
cv::threshold(image, binaryFixed, 70, 255, cv::THRESH_BINARY);
//์ ์‘์  ๊ฒฝ๊ณ„๊ฐ’ ์‚ฌ์šฉ
int blockSize = 21; //์ด์›ƒ ํ™”์†Œ์˜ ํฌ๊ธฐ
int threshold = 10; //ํ™”์†Œ๋ฅผ (ํ‰๊ท -๊ฒฝ๊ณ„ ๊ฐ’)๊ณผ ๋น„๊ต
int64 time;
time = cv::getTickCount();
cv::adaptiveThreshold(image, //์ž…๋ ฅ ์˜์ƒ
binaryAdaptive, //์ถœ๋ ฅ ์ด์ง„์˜์ƒ
255, //์ถœ๋ ฅ ์ตœ๋Œ€๊ฐ’
cv::ADAPTIVE_THRESH_MEAN_C, //์ ์‘ํ™” ๋ฐฉ๋ฒ•
cv::THRESH_BINARY, //๊ฒฝ๊ณ„ํ™” ์ข…๋ฅ˜
blockSize, //๋ธ”๋Ÿญ์˜ ์‚ฌ์ด์ฆˆ
threshold); //๊ฒฝ๊ณ„๊ฐ’ ์‚ฌ์šฉ
time = cv::getTickCount() - time;
std::cout << "time (adaptiveThreshold)= " << time << std::endl;
//์ ๋ถ„์˜์ƒ ๊ณ„์‚ฐ
IntegralImage<int, 1> integral(image);
//์ ๋ถ„๊ฒฐ๊ณผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ
std::cout << "sum= " << integral(18, 45, 30, 50) << std::endl;
cv::Mat test(image, cv::Rect(18, 45, 30, 50));
cv::Scalar t = cv::sum(test);
std::cout << "sum test=" << t[0] << std::endl;
cv::namedWindow("Fixed Threshold");
cv::imshow("Fixed Threshold", binaryFixed);
cv::namedWindow("Adaptive Threshold");
cv::imshow("Adaptive Threshold", binaryAdaptive);
cv::Mat binary = image.clone();
time = cv::getTickCount();
int nl = binary.rows; //์ค„์˜ ์ˆ˜
int nc = binary.cols; //์ค„ ๋‹น ์ด ๊ฐœ์ฒด ์ˆ˜
//์ ๋ถ„ ์˜์ƒ ๊ณ„์‚ฐ
cv::Mat iimage;
cv::integral(image, iimage, CV_32S);
//๊ฐ ํ–‰
int halfSize = blockSize / 2;
for (int j = halfSize; j < nl - halfSize - 1; j++)
{
//jํ–‰์˜ ์ฃผ์†Œ ์–ป๊ธฐ
uchar* data = binary.ptr<uchar>(j);
int* idata1 = iimage.ptr<int>(j - halfSize);
int* idata2 = iimage.ptr<int>(j + halfSize + 1);
//๊ฐ ํ–‰์˜ ํ™”์†Œ
for (int i = halfSize; i < nc - halfSize - 1; i++)
{
//ํ•ฉ ๊ณ„์‚ฐ
int sum = (idata2[i + halfSize + 1] - idata2[i - halfSize] - idata1[i + halfSize + 1] + idata1[i - halfSize]) / (blockSize*blockSize);
//์ ์‘์  ๊ฒฝ๊ณ„ํ™” ์ ์šฉ
if (data[i] < (sum - threshold))
data[i] = 0;
else
data[i] = 255;
}
}
//์ถ”๊ฐ€ ๋ฐฑ์ƒ‰ ํ…Œ๋‘๋ฆฌ
for (int j = 0; j < halfSize; j++)
{
uchar* data = binary.ptr<uchar>(j);
for (int i = 0; i < binary.cols; i++)
{
data[i] = 255;
}
}
for (int j = binary.rows - halfSize - 1; j < binary.rows; j++)
{
uchar* data = binary.ptr<uchar>(j);
for (int i = 0; i < binary.cols; i++)
{
data[i] = 255;
}
}
for (int j = halfSize; j < nl - halfSize - 1; j++)
{
uchar* data = binary.ptr<uchar>(j);
for (int i = 0; i < halfSize; i++)
{
data[i] = 255;
}
for (int i = binary.cols - halfSize - 1; i < binary.cols; i++)
{
data[i] = 255;
}
}
time = cv::getTickCount() - time;
std::cout << "time integral= " << time << std::endl;
cv::namedWindow("Adaptive Threshold (integral)");
cv::imshow("Adaptive Threshold (integral)", binary);
//์˜์ƒ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•œ ์ ์‘์  ๊ฒฝ๊ณ„ํ™”
time = cv::getTickCount();
cv::Mat filtered;
cv::Mat binaryFiltered;
//์‚ฌ๊ฐํ˜• ์ง€์—ญ ๋ฐ•์Šค ํ•„ํ„ฐ๋กœ ํ‰๊ท  ํ”ฝ์…€ ๊ณ„์‚ฐ
cv::boxFilter(image, filtered, CV_8U, cv::Size(blockSize, blockSize));
//ํ”ฝ์…€์ด (ํ‰๊ท + ๊ฒฝ๊ณ„๊ฐ’) ๋ณด๋‹ค ํฐ์ง€ ์ฒดํฌ
binaryFiltered = image >= (filtered - threshold);
time = cv::getTickCount() - time;
std::cout << "time filtered= " << time << std::endl;
cv::namedWindow("Adaptive Threshold (filtered)");
cv::imshow("Adaptive Threshold (filtered)", binaryFiltered);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 7 - ํ—ค๋” ํŒŒ์ผ๋“ค (์ด 5๊ฐœ)>
================ 1. histogram.h ================
#if !defined HISTOGRAM
#define HISTOGRAM
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
//๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ์˜์ƒ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ ์ƒ์„ฑ
class Histogram1D
{
private:
int histSize[1]; //ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ๋นˆ ๊ฐœ์ˆ˜
float hranges[2]; //๊ฐ’ ๋ฒ”์œ„
const float* ranges[1]; //๊ฐ’ ๋ฒ”์œ„๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ
int channels[1]; //์กฐ์‚ฌํ•  ์ฑ„๋„ ๋ฒˆํ˜ธ
public:
Histogram1D()
{
//1D ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ๊ธฐ๋ณธ ์ธ์ž ์ค€๋น„
histSize[0] = 256; //256๊ฐœ์˜ ๋นˆ
hranges[0] = 0.0; //0๋ถ€ํ„ฐ(ํฌํ•จ)
hranges[1] = 256.0; //256๊นŒ์ง€(์ œ์™ธ)
ranges[0] = hranges;
channels[0] = 0; //์ฑ„๋„ 0์—์„œ ๋ด„
}
//Setter & Getter
//๊ณ„์‚ฐํ•  ํžˆ์Šคํ† ๊ทธ๋žจ ์ฑ„๋„ ์ง€์ •ํ•˜๊ธฐ
//๊ธฐ๋ณธ ์ฑ„๋„์€ 0
void setChannel(int c)
{
channels[0] = c;
}
//์‚ฌ์šฉ๋œ ์ฑ„๋„ ๊ฐ€์ ธ์˜ค๊ธฐ
int getChannel()
{
return channels[0];
}
//ํ”ฝ์…€ ๊ฐ’์˜ ๋ฒ”์œ„ ์ง€์ •ํ•˜๊ธฐ
//๊ธฐ๋ณธ ๊ฐ’์€ [0, 256]
void setRange(float minValue, float maxValue)
{
hranges[0] = minValue;
hranges[1] = maxValue;
}
//์ตœ์†Œ ํ”ฝ์…€ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ
float getMinValue()
{
return hranges[0];
}
//์ตœ๋Œ€ ํ”ฝ์…€ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ
float getMaxValue()
{
return hranges[1];
}
//ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ๋นˆ ์ˆ˜ ์ง€์ •ํ•˜๊ธฐ
//๊ธฐ๋ณธ ๊ฐ’์€ 256
void setNBins(int nbins)
{
histSize[0] = nbins;
}
//ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ๋นˆ ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ
int getNBins()
{
return histSize[0];
}
//1D ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
cv::Mat getHistogram(const cv::Mat &image)
{
cv::Mat hist;
//ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
cv::calcHist(&image,
1, //๋‹จ์ผ ์˜์ƒ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ๋งŒ
channels, //๋Œ€์ƒ ์ฑ„๋„
cv::Mat(), //๋งˆ์Šคํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
hist, //๊ฒฐ๊ณผ ํžˆ์Šคํ† ๊ทธ๋žจ
1, //1D ํžˆ์Šคํ† ๊ทธ๋žจ
histSize, //๋นˆ ๊ฐœ์ˆ˜
ranges //ํ™”์†Œ ๊ฐ’์˜ ๋ฒ”์œ„
);
return hist;
}
//1D ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๊ณ„์‚ฐํ•œ ํ›„, ํžˆ์Šคํ† ๊ทธ๋žจ ์˜์ƒ์œผ๋กœ ๋ฐ˜ํ™˜
cv::Mat getHistogramImage(const cv::Mat &image, int zoom = 1)
{
//๋จผ์ € ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
cv::Mat hist = getHistogram(image);
//์˜์ƒ ์ƒ์„ฑ
return getImageOfHistogram(hist, zoom);
}
//๋ฐฑ๋ถ„์œ„์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์†Œ์Šค ์˜์ƒ์„ ๋Š˜๋ฆฌ๊ธฐ
cv::Mat stretch(const cv::Mat &image, float percentile)
{
//๋ฐฑ๋ถ„์œ„์ˆ˜์ธ ํ™”์†Œ ๊ฐœ์ˆ˜
float number = image.total()*percentile;
//๋จผ์ € ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
cv::Mat hist = getHistogram(image);
//ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์™ผ์ชฝ ๋ ์ฐพ๊ธฐ
int imin = 0;
for (float count = 0.0; imin < 256; imin++)
{
//imin์—์„œ์˜ ํ™”์†Œ ๊ฐœ์ˆ˜๊ฐ€ number๋ณด๋‹ค ๋‚ฎ์•„์•ผ ํ•จ
if ((count += hist.at<float>(imin)) >= number)
break;
}
//ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์˜ค๋ฅธ์ชฝ ๋ ์ฐพ๊ธฐ
int imax = 255;
for (float count = 0.0; imax >= 0; imax--)
{
//imax์—์„œ์˜ ํ™”์†Œ ๊ฐœ์ˆ˜๊ฐ€ number๋ณด๋‹ค ๋‚ฎ์•„์•ผ ํ•จ
if ((count += hist.at<float>(imax)) >= number)
break;
}
//๋ฃฉ์—… ํ…Œ์ด๋ธ” ์ƒ์„ฑ
int dims[1] = { 256 };
cv::Mat lookup(1, dims, CV_8U);
for (int i = 0; i < 256; i++)
{
if (i < imin) lookup.at<uchar>(i) = 0;
else if (i > imax) lookup.at<uchar>(i) = 255;
else lookup.at<uchar>(i) = cvRound(255.0*(i - imin) / (imax - imin));
}
//๋ฃฉ์—… ํ…Œ์ด๋ธ” ์ ์šฉ
cv::Mat result;
result = applyLookUp(image, lookup);
return result;
}
//์ตœ์†Œ๊ฐ’์— ๋Œ€ํ•œ bin์˜ ์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ์†Œ์Šค ์˜์ƒ ๋Š˜๋ฆฌ๊ธฐ
cv::Mat stretch(const cv::Mat &image, int minValue = 0)
{
//๋จผ์ € ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
cv::Mat hist = getHistogram(image);
//ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์™ผ์ชฝ ๋ ์ฐพ๊ธฐ
int imin = 0;
for (; imin < histSize[0]; imin++)
{
//minValue๋ณด๋‹ค ์ž‘์€ bin๋“ค์„ ๋ฌด์‹œํ•œ๋‹ค.
if (hist.at<float>(imin) > minValue)
break;
}
//ํžˆ์Šคํ† ๊ทธ๋žจ์˜ ์˜ค๋ฅธ์ชฝ ๋ ์ฐพ๊ธฐ
int imax = histSize[0] -1;
for (; imax >= 0; imax--)
{
//minValue๋ณด๋‹ค ์ž‘์€ bin๋“ค์„ ๋ฌด์‹œํ•œ๋‹ค.
if (hist.at<float>(imax) > minValue)
break;
}
//๋ฃฉ์—… ํ…Œ์ด๋ธ” ์ƒ์„ฑ
int dims[1] = { 256 };
cv::Mat lookup(1, dims, CV_8U);
for (int i = 0; i < 256; i++)
{
if (i < imin) lookup.at<uchar>(i) = 0;
else if (i > imax) lookup.at<uchar>(i) = 255;
else lookup.at<uchar>(i) = cvRound(255.0*(i - imin) / (imax - imin));
}
//๋ฃฉ์—… ํ…Œ์ด๋ธ” ์ ์šฉ
cv::Mat result;
result = applyLookUp(image, lookup);
return result;
}
//Static Methods
//ํžˆ์Šคํ† ๊ทธ๋žจ์„ ํ‘œํ˜„ํ•˜๋Š” ์˜์ƒ ์ƒ์„ฑ(์ •์  ๋ฉ”์†Œ๋“œ)
static cv::Mat getImageOfHistogram(const cv::Mat &hist, int zoom)
{
//์ตœ์†Œ ์ตœ๋Œ€ ๋นˆ ๊ฐ’ ์–ป๊ธฐ
double maxVal = 0;
double minVal = 0;
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
//ํžˆ์Šคํ† ๊ทธ๋žจ ํฌ๊ธฐ ์–ป๊ธฐ
int histSize = hist.rows;
//ํžˆ์Šคํ† ๊ทธ๋žจ์„ ํ‘œ์‹œํ•˜๋Š” ์ •์‚ฌ๊ฐํ˜• ์˜์ƒ
cv::Mat histImg(histSize*zoom, histSize*zoom, CV_8U, cv::Scalar(255));
//์ด ๋นˆ์˜ 90%์„ ์ •์ ์œผ๋กœ ์„ค์ •(์ฆ‰, ์˜์ƒ๋†’์ด)
int hpt = static_cast<int>(0.9*histSize);
//๋นˆ๋‹น ์ˆ˜์ง์„  ๊ทธ๋ฆฌ๊ธฐ
for (int h = 0; h < histSize; h++)
{
float binVal = hist.at<float>(h);
if (binVal > 0)
{
int intensity = static_cast<int>(binVal*hpt / maxVal);
cv::line(histImg, cv::Point(h*zoom, histSize*zoom), cv::Point(h*zoom, (histSize - intensity)*zoom), cv::Scalar(0), zoom);
}
}
return histImg;
}
//์†Œ์Šค ์˜์ƒ ํ‰ํ™œํ™”
static cv::Mat equalize(const cv::Mat &image)
{
cv::Mat result;
cv::equalizeHist(image, result);
return result;
}
//1์ฑ„๋„ ์ž…๋ ฅ ์ด๋ฏธ์ง€์— ๋ฃฉ์—… ํ…Œ์ด๋ธ”๋กœ ๋ณ€ํ™˜ํ•ด ์ ์šฉํ•˜๊ธฐ
static cv::Mat applyLookUp(const cv::Mat& image, //์ž…๋ ฅ์ด๋ฏธ์ง€
const cv::Mat& lookup) { //1x256 uchar ํ–‰๋ ฌ
//๊ฒฐ๊ณผ ์ด๋ฏธ์ง€
cv::Mat result;
//๋ฃฉ์—… ํ…Œ์ด๋ธ” ์ ์šฉํ•˜๊ธฐ
cv::LUT(image, lookup, result);
return result;
}
//1์ฑ„๋„ ์ž…๋ ฅ ์ด๋ฏธ์ง€์— ๋ฃฉ์—… ํ…Œ์ด๋ธ”๋กœ ๋ณ€ํ™˜ํ•ด ์ ์šฉํ•˜๊ธฐ
//์ด๊ฑด ๋ฐ˜๋ณต์ž๋ฅผ ์‚ฌ์šฉํ•œ ํ…Œ์ŠคํŠธ ๋ฒ„์ „; ํ•ญ์ƒ cv::LUT ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ
static cv::Mat applyLookUpWithIterator(const cv::Mat& image, const cv::Mat& lookup)
{
//๊ฒฐ๊ณผ ์˜์ƒ ์ง€์ •ํ•˜๊ธฐ (ํ•ญ์ƒ 1์ฑ„๋„์ด์—ฌ์•ผํ•จ)
cv::Mat result(image.rows, image.cols, CV_8U);
cv::Mat_<uchar>::iterator itr = result.begin<uchar>();
//์ž…๋ ฅ ์˜์ƒ ๋ฐ˜๋ณต ์ฒ˜๋ฆฌ
cv::Mat_<uchar>::const_iterator it = image.begin<uchar>();
cv::Mat_<uchar>::const_iterator itend = image.end<uchar>();
//๊ฐ ํ”ฝ์…€์— ๋ฃฉ์—… ์ ์šฉํ•˜๊ธฐ
for (; it != itend; ++it, ++itr)
{
*itr = lookup.at<uchar>(*it);
}
return result;
}
};
#endif
================ 2. colorhistogram.h ================
#if !defined COLHISTOGRAM
#define COLHISTOGRAM
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
class ColorHistogram
{
private:
int histSize[3]; //๊ฐ ์ฐจ์›์˜ ์‚ฌ์ด์ฆˆ
float hranges[2]; //๊ฐ’ ๋ฒ”์œ„ (3๊ฐœ์˜ ์ฐจ์›์ด ๊ฐ™๋‹ค)
const float* ranges[3]; //๊ฐ ์ฐจ์›์˜ ๊ฐ’ ๋ฒ”์œ„๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ ๋ฐฐ์—ด
int channels[3]; //๊ณ ๋ คํ•  ์ฑ„๋„
public:
ColorHistogram()
{
//์ปฌ๋Ÿฌ ํžˆ์Šคํ† ๊ทธ๋žจ ๊ธฐ๋ณธ ์ธ์ž ์ค€๋น„
//๊ฐ ์ฐจ์›์€ ์‚ฌ์ด์ฆˆ์™€ ๋ฒ”์œ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค
histSize[0] = histSize[1] = histSize[2] = 256;
hranges[0] = 0.0; //BGR ๋ฒ”์œ„๋Š” 0๋ถ€ํ„ฐ 256๊นŒ์ง€๋‹ค
hranges[1] = 256.0;
ranges[0] = hranges; //์ด ํด๋ž˜์Šค์˜ ๋ชจ๋“  ์ฑ„๋„์€ ๊ฐ™์€ ๋ฒ”์œ„๋ฅผ ๊ฐ€์ง€๊ณ ์žˆ๋‹ค.
ranges[1] = hranges;
ranges[2] = hranges;
channels[0] = 0; //B์ฑ„๋„
channels[1] = 1; //G
channels[2] = 2; //R
}
//๊ฐ๊ฐ ์ฐจ์›๋งˆ๋‹ค ํžˆ์Šคํ† ๊ทธ๋žจ ์‚ฌ์ด์ฆˆ ์„ค์ •ํ•˜๊ธฐ
void setSize(int size)
{
//๊ฐ ์ฐจ์›์€ ๊ฐ™์€ ์‚ฌ์ด์ฆˆ๋ฅผ ๊ฐ–๊ณ ์žˆ๋‹ค.
histSize[0] = histSize[1] = histSize[2] = size;
}
//ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐํ•˜๊ธฐ
cv::Mat getHistogram(const cv::Mat &image)
{
cv::Mat hist;
//BGR ์ƒ‰ ํžˆ์Šคํ† ๊ทธ๋žจ
hranges[0] = 0.0;
hranges[1] = 256.0;
channels[0] = 0;
channels[1] = 1;
channels[2] = 2;
//ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
cv::calcHist(&image,
1, //๋‹จ์ผ ์˜์ƒ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ๋งŒ
channels, //๋Œ€์ƒ ์ฑ„๋„
cv::Mat(), //๋งˆ์Šคํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
hist, //๊ฒฐ๊ณผ ํžˆ์Šคํ† ๊ทธ๋žจ
3, //3D ํžˆ์Šคํ† ๊ทธ๋žจ
histSize, //๋นˆ ๊ฐœ์ˆ˜
ranges //ํ™”์†Œ ๊ฐ’์˜ ๋ฒ”์œ„
);
return hist;
}
//๊ณผ๋„ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋ชจ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด ํฌ์†Œ ํ–‰๋ ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•
cv::SparseMat getSparseHistogram(const cv::Mat &image)
{
cv::SparseMat hist(3, //์ฐจ์›์˜ ๊ฐœ์ˆ˜
histSize, //๊ฐ ์ฐจ์›์˜ ํฌ๊ธฐ
CV_32F);
//BGR ์ƒ‰ ํžˆ์Šคํ† ๊ทธ๋žจ
hranges[0] = 0.0;
hranges[1] = 256.0;
channels[0] = 0;
channels[1] = 1;
channels[2] = 2;
//ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐํ•˜๊ธฐ
cv::calcHist(&image,
1, //๋‹จ์ผ ์˜์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ๋งŒ
channels, //๋Œ€์ƒ ์ฑ„๋„
cv::Mat(), //๋งˆ์Šคํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
hist, //๊ฒฐ๊ณผ ํžˆ์Šคํ† ๊ทธ๋žจ
3, //3D ํžˆ์Šคํ† ๊ทธ๋žจ
histSize, //๋นˆ ๊ฐœ์ˆ˜
ranges //ํ™”์†Œ ๊ฐ’์˜ ๋ฒ”์œ„
);
return hist;
}
//๋งˆ์Šคํฌ๋กœ 1D ์ƒ‰์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐํ•˜๊ธฐ
//BGR ์› ์˜์ƒ์„ HSV๋กœ ๋ณ€ํ™˜
//๋‚ฎ์€ ์ฑ„๋„๋ฅผ ๊ฐ–๋Š” ํ™”์†Œ ๋ฌด์‹œ
cv::Mat getHueHistogram(const cv::Mat &image, int minSaturation = 0)
{
cv::Mat hist;
//HSV์ปฌ๋Ÿฌ ๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
//์‚ฌ์šฉํ•  ๋งˆ์Šคํฌ(๋˜๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ)
cv::Mat mask;
//๋งŒ์•ฝ ๋งˆ์Šคํฌ๊ฐ€ ํ•„์š”ํ•˜์‹ค์‹œ ์ƒ์„ฑ
if (minSaturation > 0)
{
//3์ฑ„๋„์„ 3๊ฐœ์˜ ์˜์ƒ์œผ๋กœ ๋ถ„๋ฆฌ
std::vector<cv::Mat> v;
cv::split(hsv, v);
//๋‚ฎ์€ ์ฑ„๋„๋ฅผ ๊ฐ–๋Š” ํ™”์†Œ๋ฅผ ์ œ์™ธ
cv::threshold(v[1], mask, minSaturation, 255, cv::THRESH_BINARY);
}
//1D ์ƒ‰์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ์„ ์œ„ํ•œ ์ธ์ž ์ค€๋น„
hranges[0] = 0.0; //๋ฒ”์œ„๋Š” 0๋ถ€ํ„ฐ 180๊นŒ์ง€์ž„
hranges[1] = 180.0;
channels[0] = 0; //์ƒ‰์ƒ ์ฑ„๋„
//ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
cv::calcHist(&hsv,
1, //๋‹จ์ผ ์˜์ƒ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ๋งŒ
channels, //๋Œ€์ƒ ์ฑ„๋„
mask, //์ด์ง„ ๋งˆ์Šคํฌ
hist, //๊ฒฐ๊ณผ ํžˆ์Šคํ† ๊ทธ๋žจ
1, //1D ํžˆ์Šคํ† ๊ทธ๋žจ
histSize, //๋นˆ ๊ฐœ์ˆ˜
ranges //ํ™”์†Œ ๊ฐ’์˜ ๋ฒ”์œ„
);
return hist;
}
//2D ab๊ณต๊ฐ„ ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐํ•˜๊ธฐ
//BGR ์› ์˜์ƒ์„ Lab๋กœ ๋ณ€ํ™˜
//๋‚ฎ์€ ์ฑ„๋„๋ฅผ ๊ฐ–๋Š” ํ™”์†Œ ๋ฌด์‹œ
cv::Mat getabHistogram(const cv::Mat &image)
{
cv::Mat hist;
//Lab์ปฌ๋Ÿฌ ๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜
cv::Mat lab;
cv::cvtColor(image, lab, CV_BGR2Lab);
//2D ์ƒ‰์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ์„ ์œ„ํ•œ ์ธ์ž ์ค€๋น„
hranges[0] = 0.0;
hranges[1] = 256.0;
channels[0] = 1; //๋‘ ๊ฐœ์˜ ๋Œ€์ƒ ์ฑ„๋„์€ ab์ž„
channels[1] = 2;
//ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
cv::calcHist(&lab,
1, //๋‹จ์ผ ์˜์ƒ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ๋งŒ
channels, //๋Œ€์ƒ ์ฑ„๋„
cv::Mat(), //๋งˆ์Šคํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
hist, //๊ฒฐ๊ณผ ํžˆ์Šคํ† ๊ทธ๋žจ
2, //2D ํžˆ์Šคํ† ๊ทธ๋žจ
histSize, //๋นˆ ๊ฐœ์ˆ˜
ranges //ํ™”์†Œ ๊ฐ’์˜ ๋ฒ”์œ„
);
return hist;
}
};
#endif
================ 3. contentFinder.h ================
#if !defined OFINDER
#define OFINDER
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
class ContentFinder
{
private:
//ํžˆ์Šคํ† ๊ทธ๋žจ ํŒŒ๋ผ๋ฏธํ„ฐ
float hranges[2];
const float* ranges[3];
int channels[3];
float threshold; //๊ฒฝ๊ณ„๊ฐ’ ๊ฒฐ์ •
cv::Mat histogram; //ํฌ์†Œํ™”ํ•˜์ง€ ์•Š์€ ํžˆ์Šคํ† ๊ทธ๋žจ
cv::SparseMat shistogram; //ํฌ์†Œํ™”ํ•œ ํžˆ์Šคํ† ๊ทธ๋žจ
bool isSparse;
public:
ContentFinder() : threshold(0.1f), isSparse(false)
{
//์ด ํด๋ž˜์Šค์—์„œ ๋ชจ๋“  ์ฑ„๋„์€ ๊ฐ™์€ ๋ฒ”์œ„์ž„
ranges[0] = hranges;
ranges[1] = hranges;
ranges[2] = hranges;
}
//Setter & Getter
//ํžˆ์Šคํ† ๊ทธ๋žจ์˜ [0, 1] ๊ฐ’์—์„œ ๊ฒฝ๊ณ„ ๊ฐ’ ์„ค์ •
void setThreshold(float t)
{
threshold = t;
}
//๊ฒฝ๊ณ„๊ฐ’ ์–ป๊ธฐ
float getThreshold()
{
return threshold;
}
//๊ธฐ์ค€ ํžˆ์Šคํ† ๊ทธ๋žจ ์„ค์ •
void setHistogram(const cv::Mat& h)
{
isSparse = false;
cv::normalize(h, histogram, 1.0);
}
//๊ธฐ์ค€ ํžˆ์Šคํ† ๊ทธ๋žจ ์„ค์ • (ํฌ์†Œํ™”)
void setHistogram(const cv::SparseMat& h)
{
isSparse = true;
cv::normalize(h, shistogram, 1.0, cv::NORM_L2);
}
//๋‹จ์ˆœํ™”ํ•œ ๋ฒ„์ „
//๋ฒ”์œ„๊ฐ€ [0, 256]์ธ ๋ชจ๋“  ์ฑ„๋„ ์‚ฌ์šฉ
cv::Mat find(const cv::Mat& image)
{
cv::Mat result;
hranges[0] = 0.0;
hranges[1] = 256.0;
channels[0] = 0;
channels[1] = 1;
channels[2] = 2;
return find(image, hranges[0], hranges[1], channels);
}
//ํžˆ์Šคํ† ๊ทธ๋žจ์— ์†ํ•˜๋Š” ํ™”์†Œ ์ฐพ๊ธฐ
cv::Mat find(const cv::Mat& image, float minValue, float maxValue, int *channels)
{
cv::Mat result;
hranges[0] = minValue;
hranges[1] = maxValue;
if (isSparse) //ํžˆ์Šคํ† ๊ทธ๋žจ ํ˜•ํƒœ์— ๊ธฐ๋ฐ˜์„ ๋‘” ์ ์ž˜ํ•œ ํ•จ์ˆ˜ ํ˜ธ์ถœ
{
//ํžˆ์Šคํ† ๊ทธ๋žจ ์ฐจ์›์€ ์ฑ„๋„ ๋ชฉ๋ก๊ณผ ์ผ์น˜
for (int i = 0; i < shistogram.dims(); i++)
this->channels[i] = channels[i];
cv::calcBackProject(&image,
1, //ํ•œ ๋ฒˆ์— ์˜์ƒ 1๊ฐœ๋งŒ ์‚ฌ์šฉ
channels, //์˜์ƒ ์ฑ„๋„์— ์†ํ•˜๋Š” ํžˆ์Šคํ† ๊ทธ๋žจ ์ฐจ์›์„ ์ง€์ •ํ•œ ๋ฐฑํ„ฐ
shistogram, //์‚ฌ์šฉํ•  ํžˆ์Šคํ† ๊ทธ๋žจ
result, //์—ญํˆฌ์˜ ์˜์ƒ
ranges, //์ฐจ์›๋‹น ๊ฐ’์˜ ๋ฒ”์œ„
255.0 //ํ™•๋ฅ  ๊ฐ’์˜ 1์„ 255๋กœ ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•ด ์„ ํƒํ•œ ์žฌ์กฐ์ • ์ธ์ž
);
}
else
{
//ํžˆ์Šคํ† ๊ทธ๋žจ ์ฐจ์›์€ ์ฑ„๋„ ๋ชฉ๋ก๊ณผ ์ผ์น˜
for (int i = 0; i < histogram.dims; i++)
this->channels[i] = channels[i];
cv::calcBackProject(&image,
1, //ํ•œ ๋ฒˆ์— ์˜์ƒ 1๊ฐœ๋งŒ ์‚ฌ์šฉ
channels, //์˜์ƒ ์ฑ„๋„์— ์†ํ•˜๋Š” ํžˆ์Šคํ† ๊ทธ๋žจ ์ฐจ์›์„ ์ง€์ •ํ•œ ๋ฐฑํ„ฐ
histogram, //์‚ฌ์šฉํ•  ํžˆ์Šคํ† ๊ทธ๋žจ
result, //์—ญํˆฌ์˜ ์˜์ƒ
ranges, //์ฐจ์›๋‹น ๊ฐ’์˜ ๋ฒ”์œ„
255.0 //ํ™•๋ฅ  ๊ฐ’์˜ 1์„ 255๋กœ ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•ด ์„ ํƒํ•œ ์žฌ์กฐ์ • ์ธ์ž
);
}
//์ด์ง„ ์˜์ƒ์„ ์–ป๊ธฐ ์œ„ํ•ด ์—ญํˆฌ์˜์„ ๊ฒฝ๊ณ„ํ™”
if (threshold > 0.0)
cv::threshold(result, result, 255.0*threshold, 255.0, cv::THRESH_BINARY);
return result;
}
};
#endif
================ 4. imageComparator.h ================
#if !defined ICOMPARATOR
#define ICOMPARATOR
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include "colorhistogram.h"
class ImageComparator
{
private:
cv::Mat refH; //๊ธฐ์ค€ ํžˆ์Šคํ† ๊ทธ๋žจ
cv::Mat inputH; //์ž…๋ ฅ์˜์ƒ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ
ColorHistogram hist; //์ƒ์„ฑํ•  ํžˆ์Šคํ† ๊ทธ๋žจ
int nBins; //๊ฐ ์ปฌ๋Ÿฌ์ฑ„๋„์— ์‚ฌ์šฉ๋œ ๋นˆ์˜ ๊ฐœ์ˆ˜
public:
ImageComparator() :nBins(8) {}
//ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๋น„๊ตํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ์˜ ๊ฐœ์ˆ˜ ์„ค์ •
void setNumberOfBins(int bins)
{
nBins = bins;
}
int getNumberOfBins()
{
return nBins;
}
//๊ธฐ์ค€ ์˜์ƒ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐ
void setReferenceImage(const cv::Mat& image)
{
hist.setSize(nBins);
refH = hist.getHistogram(image);
}
//๋‘ BGR ํžˆ์Šคํ† ๊ทธ๋žจ์„ ์‚ฌ์šฉํ•ด ์˜์ƒ ๋น„๊ต
double compare(const cv::Mat& image)
{
inputH = hist.getHistogram(image);
//๊ต์ฐจ์ ์„ ์ด์šฉํ•œ ํžˆ์Šคํ† ๊ทธ๋žจ ๋น„๊ต
return cv::compareHist(refH, inputH, cv::HISTCMP_INTERSECT);
}
};
#endif
================ 5. integral.h ================
#if !defined IINTEGRAL
#define IINTEGRAL
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <vector>
template <typename T, int N>
class IntegralImage
{
cv::Mat integralImage;
public:
IntegralImage(cv::Mat image)
{
//(๋น„์šฉ์ด ๋งŽ์ด ๋“œ๋Š”) ์ ๋ถ„ ์˜์ƒ ๊ณ„์‚ฐ
cv::integral(image, integralImage, cv::DataType<T>::type);
}
//4๊ฐœ์˜ ํ™”์†Œ ์ ‘๊ทผ์œผ๋กœ๋ถ€ํ„ฐ ์ž„์˜ ํฌ๊ธฐ์˜ ๋ถ€๋ถ„ ์˜์—ญ์— ๊ฑธ์ณ ํ•ฉ์„ ๊ณ„์‚ฐํ•˜๊ธฐ
cv::Vec<T, N> operator() (int xo, int yo, int width, int height)
{
//(xo, yo)์— ์žˆ๋Š” ๋†’์ด * ๋„ˆ๋น„์˜ ํฌ๊ธฐ์ธ ์œˆ๋„์šฐ
return (integralImage.at<cv::Vec<T, N> >(yo + height, xo + width)
- integralImage.at<cv::Vec<T, N> >(yo + height, xo)
- integralImage.at<cv::Vec<T, N> >(yo, xo + width)
+ integralImage.at<cv::Vec<T, N> >(yo, xo));
}
};
//์ด์ง„ ํ‰๋ฉด์œผ๋กœ ๊ตฌ์„ฑ๋œ ๋‹ค์ฑ„๋„ ์˜์ƒ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ
//nPlanes๋Š” ๋ฐ˜๋“œ์‹œ 2์˜ ์ง€์ˆ˜ ์Šน์ด์–ด์•ผ ํ•จ
void convertToBinaryPlanes(const cv::Mat& input, cv::Mat& output, int nPlanes)
{
//์ œ์™ธํ•˜๊ธฐ ์œ„ํ•œ ๋น„ํŠธ ๊ฐœ์ˆ˜
int n = 8 - static_cast<int>(log(static_cast<double>(nPlanes)) / log(2.0));
//์ตœํ•˜์œ„ ๋น„ํŠธ ์ œ๊ฑฐ์— ์‚ฌ์šฉํ•˜๋Š” ๋งˆ์Šคํฌ
uchar mask = 0xFF << n; // ์˜ˆ๋ฅผ ๋“ค์–ด div=16 ๋ผ๋ฉด mask=0xF0
//์ด์ง„์˜์ƒ์˜ ๋ฐฑํ„ฐ ์ƒ์„ฑ
std::vector<cv::Mat> planes;
//์ตœํ•˜์œ„ ๋น„ํŠธ๋“ค์„ ์ œ๊ฑฐํ•ด nBins๋ฅผ ์ค„์ž„
cv::Mat reduced = input & mask;
//๊ฐ ์ด์ง„์˜์ƒ ํ‰๋ฉด ๊ณ„์‚ฐ
for (int i = 0; i < nPlanes; i++)
{
//๊ฐ ํ™”์†Œ์˜ 1์€ i<<shift์™€ ๋™์ผํ•˜๋‹ค
planes.push_back((reduced == (i << n)) & 0x1);
}
//๋‹ค์ฑ„๋„ ์˜์ƒ ์ƒ์„ฑํ•˜๊ธฐ
cv::merge(planes, output);
}
#endif
5. ํ˜•ํƒœํ•™ ์—ฐ์‚ฐ์œผ๋กœ ์˜์ƒ ๋ณ€ํ™˜(Transforming images with morphological operations)
- ์ˆ˜ํ•™์  ํ˜•ํƒœํ•™์€ ์ด์‚ฐ ์˜์ƒ ๋ถ„์„๊ณผ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด 1960๋…„๋Œ€์— ๋‚˜์™”๋˜ ์ด๋ก , ๊ธฐ๋ณธ ์„ฑ๋ถ„์€ ๊ตฌ์กฐ์š”์†Œ(structuring element)์ด๋‹ค. ๊ตฌ์กฐ์š”์†Œ๋Š” ๊ณ ์ •์ (anchor point)๊ฐ€ ์žˆ๋Š” ํ™”์†Œ์˜ ๊ตฌ์„ฑ์ด๋‹ค.
๊ตฌ์กฐ์š”์†Œ๋Š” ์‚ฌ๊ฐํ˜•, ์›, ๋‹ค์ด์•„๋ชฌ๋“œ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ๋ชจ์–‘์„ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค. ํ˜•ํƒœํ•™ ์šฉ์–ด๋กœ ์˜์ƒ์˜ ๋ณด์ˆ˜๋Š” ์ด์ง„ ์˜์ƒ์„ ๋ฐ˜์ „ํ•œ ๊ฒƒ์„ ๋œปํ•œ๋‹ค.
- ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ์˜ ํ˜•ํƒœํ•™์„ ์ƒ๊ฐํ•  ๋•Œ ์‚ฐ์„ ์ƒ๊ฐํ•˜๋ฉด ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋‹ค.
1) ์นจ์‹(erosion), ํŒฝ์ฐฝ(dilation)์€ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœํ•™ ์—ฐ์‚ฐ์ž(ํ•„ํ„ฐ์ด๋‹ค). ์šฐ์„ , ์นจ์‹์€ ํ˜„์žฌ ํ™”์†Œ๋ฅผ ์ •์˜๋œ ํ™”์†Œ ์ง‘ํ•ฉ์—์„œ ์ฐพ์€ ์ตœ์†Œ ํ™”์†Œ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ํŒฝ์ฐฝ์€ ๋ฐ˜๋Œ€๋‹ค.
๋” ํฐ ๊ตฌ์กฐ์š”์†Œ๋‚˜ ์—ฌ๋Ÿฌ ๋ฒˆ ์˜์ƒ์„ ์นจ์‹/ํŒฝ์ฐฝํ•˜๋ฉด ๋” ๊ฐ•ํ•˜๊ฒŒ ๋œ๋‹ค. ์ œ์ž๋ฆฌ ์ฒ˜๋ฆฌ(์ž…๋ ฅ์˜์ƒ=๊ฒฐ๊ณผ์˜์ƒ)์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
2) ์—ด๋ฆผ(opening), ๋‹ซํž˜(closing)์€ ๊ณ ์ˆ˜์ค€ ํ˜•ํƒœํ•™ ํ•„ํ„ฐ์ด๋‹ค. cv::morphologyEx()ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜๋Š” ์› ์˜์ƒ์„ ํŒฝ์ฐฝ> ์นจ์‹ ์‹œํ‚ค๋ฉด ๋‹ซํžŒ ์˜์ƒ, ์นจ์‹ > ํŒฝ์ฐฝ ์‹œํ‚ค๋ฉด ์—ด๋ฆฐ ์˜์ƒ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
๋‹ซํž˜ ํ•„ํ„ฐ๋Š” ์—ฌ๋Ÿฌ ์ธ์ ‘ํ•œ ๊ฐ์ฒด๋ฅผ ์—ฐ๊ฒฐ. ๊ตฌ์กฐ ์š”์†Œ๋ฅผ ์™„์ „ํžˆ ํฌํ•จํ•˜๊ธฐ์—” ๋„ˆ๋ฌด๋‚˜ ์ž‘์€ ํ™€์ด๋‚˜ ํ‹ˆ(gap)์„ ๋ชจ๋‘ ์ œ๊ฑฐํ•œ๋‹ค.
์—ด๋ฆผ ํ•„ํ„ฐ๋Š” ์ƒํ˜ธ์ ์œผ๋กœ ์žฅ๋ฉด์— ์žˆ๋Š” ์—ฌ๋Ÿฌ ์ž‘์€ ๊ฐ์ฒด๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.
3) ๊ธฐ์šธ๊ธฐ(gradient)๋Š” ์˜์ƒ์˜ ์—์ง€ ์ถ”์ถœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ํฅ๋ฏธ๋กœ์šด ํ•„ํ„ฐ๋กœ cv::morphologyEx()ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์›๋ฆฌ๋Š” ํŒฝ์ฐฝํ•œ ์˜์ƒ์—์„œ ์นจ์‹ํ•œ ์˜์ƒ์˜ ์ฐจ๋ฅผ ๊ณ„์‚ฐํ•˜๋ฉด ๊ฒ€์ถœ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ฒŒ ์›์˜์ƒ๊ณผ ์นจ์‹, ํŒฝ์ฐฝ์˜ ์ฐจ๋ฅผ ๊ตฌํ•ด๋„ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.
4) ํƒ‘ํ–‡๋ณ€ํ™˜(top-hat transform)์€ ์˜์ƒ์—์„œ ์ž‘์€ ์ง€์—ญ ์ „๊ฒฝ์„ ์ถ”์ถœํ•˜๋Š” ๋ฐ, ์ด ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ธ”๋ž™ํƒ‘ํ–‡๋ณ€ํ™˜์€ ๊ฒ€์€์ƒ‰์„ ์ถ”์ถœํ•œ๋‹ค. ์›๋ฆฌ๋Š” ์—ด๋ฆผ, ๋‹ซํž˜๊ณผ ์› ์˜์ƒ์˜ ์ฐจ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ•œ๋‹ค.
์—ด๋ฆฌ๋ฉด ์ง€์—ญ ๋ด‰์šฐ๋ฆฌ(local leak)=์ถ”์ถœํ•˜๋ ค๋Š” ์ „๊ฒฝ ๊ฐ์ฒด๊ฐ€ ์ œ๊ฑฐ๋œ๋‹ค. ๋‹ซํžˆ๋ฉด ์•„๋ž˜์ชฝ ๋ด‰์šฐ๋ฆฌ๊ฐ€ ์ œ๊ฑฐ = ๋ธ”๋žซ ํƒ‘ํ–‡์˜ ์›๋ฆฌ๋‹ค.
5) ์›Œํ„ฐ์‰๋“œ๋ณ€ํ™˜(watershed transformation)์€ ๋™์งˆ ์˜์—ญ ๋ถ„ํ• ์— ์‚ฌ์šฉ๋˜๋Š” ์ธ๊ธฐ ์žˆ๋Š” ์˜์ƒ์ฒ˜๋ฆฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค. ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์˜์ƒ์„ ์œ„์ƒ์  ์ง€ํ˜•์œผ๋กœ ๋ดค์„ ๋•Œ, ๋™์งˆ ์˜์—ญ์€ ์ƒ๋Œ€์ ์œผ๋กœ ๊ฐ€ํŒŒ๋ฅธ ์—์ง€๋กœ ๊ตฌ๋ถ„๋œ ํ‰ํƒ„ํ•œ ์œ ์—ญ์— ๋Œ€์‘ํ•œ๋‹ค๋Š” ์•„์ด๋””์–ด์— ์˜๊ฑฐํ•œ๋‹ค.
cv::watershed()ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์˜์ƒ ๋ถ„ํ• ์˜ ์ •์˜๋ฅผ ์•ˆ๋‚ดํ•˜๋Š” ๋ฏธ๋ฆฌ ์ •์˜๋œ ๋งˆ์ปค์˜ ์ง‘ํ•ฉ์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋งˆ์ปค์˜ ์ง‘ํ•ฉ์€ ๊ฒ€์€์ƒ‰0(์•Œ์ˆ˜์—†๋Š”ํ™”์†Œ), ํฐ์ƒ‰, ํšŒ์ƒ‰๋“ฑ์œผ๋กœ ์ „๊ฒฝ๊ณผ ๋ฐฐ๊ฒฝ์„ ๊ตฌ๋ถ„์ง“๋Š” ์˜์ƒ์ด๋‹ค. ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ๋งˆ์ปค๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐฐ๊ฒฝ๋ถ€๋ถ„์— ํฐ ์‚ฌ๊ฐํ˜• ํ…Œ๋‘๋ฆฌ, ์ „๊ฒฝ์— ์ž‘์€ ์‚ฌ๊ฐํ˜• ํ…Œ๋‘๋ฆฌ ์ด๋Ÿฐ์‹์œผ๋กœ๋„.
์›Œํ„ฐ์‰๋“œ์˜ ์„  ๋ถ€๋ถ„์€ -1๋ฅผ ํ—ˆ์šฉํ•˜๋ฉฐ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์›Œํ„ฐ์‰๋“œ ์„ ๋งŒ ๋ฝ‘์•„๋‚ด๊ธฐ ์œ„ํ•ด ์„ ํ˜•๋ณ€ํ™˜ 0 (-1*255+255 = 0)์„ ์ ์šฉํ•œ๋‹ค. ๋‚˜๋จธ์ง„ ๋‹ค 255
6) MSER(Maximally Stable External Region)์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์˜์ƒ์˜ ์˜๋ฏธ์žˆ๋Š” ์˜์—ญ์„ ์ถ”์ถœํ•˜๊ธฐ ์œ„ํ•ด ๋™์ผํ•œ ์นจ์ˆ˜ ์œ ์ถ”(immersion analogy)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
๊ณ„์‚ฐํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€ CV::Feature2D ์•ˆ์—์žˆ๋Š” cv::MSER์ด๋‹ค.
<์ฝ”๋“œ 1 - ํ˜•ํƒœํ•™ ํ•„ํ„ฐ์™€ ํ˜•ํƒœํ•™ ์—ฐ์‚ฐ์ž>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main()
{
//์ž…๋ ฅ ์˜์ƒ ์ฝ๊ธฐ
cv::Mat image = cv::imread("../images/binary.bmp");
if (!image.data) return 0;
//์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Image");
cv::imshow("Image", image);
//์˜์ƒ ์นจ์‹
//3*3 ๊ธฐ๋ณธ ๊ตฌ์กฐ์š”์†Œ๋กœ (SE)
cv::Mat eroded;
cv::erode(image, eroded, cv::Mat());
//์นจ์‹ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Eroded Image");
cv::imshow("Eroded Image", eroded);
//์˜์ƒ ํŒฝ์ฐฝ
cv::Mat dilated; //๋ชฉ์ ์˜์ƒ
cv::dilate(image, dilated, cv::Mat());
//ํŒฝ์ฐฝ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Dilated Image");
cv::imshow("Dilated Image", dilated);
//๋” ํฐ ๊ตฌ์กฐ์š”์†Œ(SE)๋กœ ์˜์ƒ ์นจ์‹
//1์„ ๋ชจ๋‘ ํฌํ•จํ•˜๋Š” 7*7 ํ–‰๋ ฌ ์ƒ์„ฑ
cv::Mat element(7, 7, CV_8U, cv::Scalar(1));
//๊ตฌ์กฐ์š”์†Œ(SE)๋กœ ์˜์ƒ ์นจ์‹
cv::erode(image, eroded, element);
//๋” ํฐ ์นจ์‹ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Eroded Image (7x7)");
cv::imshow("Eroded Image (7x7)", eroded);
//์˜์ƒ์„ ์„ธ ๋ฒˆ ์นจ์‹
cv::erode(image, eroded, cv::Mat(), cv::Point(-1, -1), 3);
//3๋ฒˆ ์นจ์‹ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Eroded Image (3 times)");
cv::imshow("Eroded Image (3 times)", eroded);
//์˜์ƒ ๋‹ซํž˜
cv::Mat element5(5, 5, CV_8U, cv::Scalar(1));
cv::Mat closed;
cv::morphologyEx(image, closed, //์ž…๋ ฅ ์˜์ƒ๊ณผ ๊ฒฐ๊ณผ ์˜์ƒ
cv::MORPH_CLOSE, //์—ฐ์‚ฐ์ž ์ฝ”๋“œ
element5); //๊ตฌ์กฐ ์š”์†Œ(SE)
//๋‹ซํžŒ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Closed Image");
cv::imshow("Closed Image", closed);
//์˜์ƒ ์—ด๋ฆผ
cv::Mat opened;
cv::morphologyEx(image, opened, cv::MORPH_OPEN, element5);
//์—ด๋ฆฐ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Opened Image");
cv::imshow("Opened Image", opened);
//๋ช…์‹œ์  ๋‹ซํž˜
//1. ์› ์˜์ƒ์„ ํŒฝ์ฐฝ
cv::Mat result;
cv::dilate(image, result, element5);
//2. ํŒฝ์ฐฝํ•œ ์˜์ƒ์„ ์ œ์ž๋ฆฌ์—์„œ ์นจ์‹
cv::erode(result, result, element5);
//๋ช…์‹œ์  ๋‹ซํžŒ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Closed Image (2)");
cv::imshow("Closed Image (2)", result);
//๋‹ซํžˆ๊ณ  ์—ด๋ฆฐ ์˜์ƒ
cv::morphologyEx(image, image, cv::MORPH_CLOSE, element5);
cv::morphologyEx(image, image, cv::MORPH_OPEN, element5);
//๋‹ซํžˆ๊ณ  ์—ด๋ฆฐ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Closed|Opened Image");
cv::imshow("Closed|Opened Image", image);
cv::imwrite("binaryGroup.bmp", image);
//์ž…๋ ฅ ์˜์ƒ ์ฝ๊ธฐ
image = cv::imread("../images/binary.bmp");
if (!image.data) return 0;
//์—ด๋ฆฌ๊ณ  ๋‹ซํžŒ ์˜์ƒ
cv::morphologyEx(image, image, cv::MORPH_OPEN, element5);
cv::morphologyEx(image, image, cv::MORPH_CLOSE, element5);
//์—ด๋ฆฌ๊ณ  ๋‹ซํžŒ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Opened|Closed Image");
cv::imshow("Opened|Closed Image", image);
//์ž…๋ ฅ ์˜์ƒ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ (๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ)
image = cv::imread("../images/boldt.jpg", 0);
if (!image.data) return 0;
//3x3 ๊ตฌ์กฐ์š”์†Œ(SE)๋ฅผ ์‚ฌ์šฉํ•ด ๊ธฐ์šธ๊ธฐ ์˜์ƒ ์–ป๊ธฐ
cv::morphologyEx(image, result, cv::MORPH_GRADIENT, cv::Mat());
//ํ˜•ํƒœํ•™ ์™ธ๊ฐ์„  ์˜์ƒ ํ‘œ์‹œ (๋ฐ˜์ „)
cv::namedWindow("Edge Image");
cv::imshow("Edge Image", 255 - result);
//๊ฒฝ๊ณ„๊ฐ’ ์ ์šฉํ•ด ์ด์ง„ ์˜์ƒ ์–ป๊ธฐ
int threshold(80);
cv::threshold(result, result, threshold, 255, cv::THRESH_BINARY);
//๊ฒฝ๊ณ„๊ฐ’ ์ ์šฉ๋œ ์™ธ๊ณฝ์„  ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Thresholded Edge Image");
cv::imshow("Thresholded Edge Image", result);
//์ž…๋ ฅ ์˜์ƒ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ (๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ)
image = cv::imread("../images/book.jpg", 0);
if (!image.data) return 0;
//๋ณด๊ธฐ์‰ฝ๊ฒŒ ์˜์ƒ ํšŒ์ „ํ•ด ํ‘œ์‹œ
cv::transpose(image, image);
cv::flip(image, image, 0);
//7x7 ๊ตฌ์กฐ์š”์†Œ(SE)๋ฅผ ์‚ฌ์šฉํ•ด ๋ธ”๋ž™ ํƒ‘ํ–‡ ๋ณ€ํ™˜ ์ ์šฉ
cv::Mat element7(7, 7, CV_8U, cv::Scalar(1));
cv::morphologyEx(image, result, cv::MORPH_BLACKHAT, element7);
//ํƒ‘ํ–‡ ์˜์ƒ ํ‘œ์‹œ (๋ฐ˜์ „)
cv::namedWindow("7x7 Black Top-hat Image");
cv::imshow("7x7 Black Top-hat Image", 255 - result);
//๊ฒฝ๊ณ„๊ฐ’ ์ ์šฉํ•ด ์ด์ง„ ์˜์ƒ ์–ป๊ธฐ
threshold = 25;
cv::threshold(result, result, threshold, 255, cv::THRESH_BINARY);
//๊ฒฝ๊ณ„๊ฐ’ ์ ์šฉ๋œ ๋ธ”๋ž™ ํƒ‘ํ–‡ ๋ณ€ํ™˜ ์˜์ƒ ํ‘œ์‹œ (๋ฐ˜์ „)
cv::namedWindow("Thresholded Black Top-hat");
cv::imshow("Thresholded Black Top-hat", 255 - result);
//7x7 ๊ตฌ์กฐ์š”์†Œ(SE)๋ฅผ ์‚ฌ์šฉํ•ด ๋‹ซํž˜ ์ ์šฉ
cv::morphologyEx(image, result, cv::MORPH_CLOSE, element7);
//7x7 ๋‹ซํžŒ ์˜์ƒ ํ‘œ์‹œ (๋ฐ˜์ „)
cv::namedWindow("7x7 Closed Image");
cv::imshow("7x7 Closed Image", 255 - result);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 2 - ์›Œํ„ฐ์‰๋“œ๋ฅผ ์ด์šฉํ•œ ์˜์ƒ ๋ถ„ํ•  (ํ—ค๋”ํŒŒ์ผ ์ฝ”๋“œ ํฌํ•จ)>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include "watershedSegmentation.h"
int main()
{
//์ž…๋ ฅ ์˜์ƒ ์ฝ๊ธฐ
cv::Mat image = cv::imread("../images/group.jpg");
if (!image.data) return 0;
//์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Original Image");
cv::imshow("Original Image", image);
//์ด์ง„ ๋งต ๊ฐ€์ ธ์˜ค๊ธฐ
cv::Mat binary;
binary = cv::imread("../images/binary.bmp", 0);
//์ด์ง„ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Binary Image");
cv::imshow("Binary Image", binary);
//์žก์Œ๊ณผ ๋” ์ž‘์€ ๊ฐ์ฒด ์ œ๊ฑฐ
cv::Mat fg;
cv::erode(binary, fg, cv::Mat(), cv::Point(-1, -1), 4);
//์ „๊ฒฝ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Foreground Image");
cv::imshow("Foreground Image", fg);
//๊ฐ์ฒด ์—†๋Š” ์˜์ƒ ํ™”์†Œ ์‹๋ณ„
cv::Mat bg;
cv::dilate(binary, bg, cv::Mat(), cv::Point(-1, -1), 4);
cv::threshold(bg, bg, 1, 128, cv::THRESH_BINARY_INV);
//๋ฐฐ๊ฒฝ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Background Image");
cv::imshow("Background Image", bg);
//๋งˆ์ปค ์˜์ƒ ์ƒ์„ฑ
cv::Mat markers(binary.size(), CV_8U, cv::Scalar(0));
markers = fg + bg;
cv::namedWindow("Markers");
cv::imshow("Markers", markers);
//์›Œํ„ฐ์‰๋“œ ๋ถ„ํ•  ๊ฐ์ฒด ์ƒ์„ฑ
WatershedSegmenter segmenter;
//๋งˆ์ปค๋ฅผ ์„ค์ •ํ•œ ํ›„ ์ฒ˜๋ฆฌ
segmenter.setMarkers(markers);
segmenter.process(image);
//๋ถ„ํ•  ๊ฒฐ๊ณผ ํ‘œ์‹œ
cv::namedWindow("Segmentation");
cv::imshow("Segmentation", segmenter.getSegmentation());
//์›Œํ„ฐ์‰๋“œ ํ‘œ์‹œ
cv::namedWindow("Watersheds");
cv::imshow("Watersheds", segmenter.getWatersheds());
//๋˜ ๋‹ค๋ฅธ ์ด๋ฏธ์ง€ ์—ด๊ธฐ
image = cv::imread("../images/tower.jpg");
//๋ฐฐ๊ฒฝ ํ™”์†Œ ์‹๋ณ„
cv::Mat imageMask(image.size(), CV_8U, cv::Scalar(0));
cv::rectangle(imageMask, cv::Point(5, 5), cv::Point(image.cols - 5, image.rows - 5), cv::Scalar(255), 3);
//(์˜์ƒ ๊ฐ€์šด๋ฐ์˜) ์ „๊ฒฝ ํ™”์†Œ ์‹๋ณ„
cv::rectangle(imageMask, cv::Point(image.cols / 2 - 10, image.rows / 2 - 10), cv::Point(image.cols / 2 + 10, image.rows / 2 + 10), cv::Scalar(1), 10);
//๋งˆ์ปค๋ฅผ ์„ค์ •ํ•œ ํ›„ ์ฒ˜๋ฆฌ
segmenter.setMarkers(imageMask);
segmenter.process(image);
//์˜์ƒ๊ณผ ๋งˆ์ปค ํ‘œ์‹œ
cv::rectangle(image, cv::Point(5, 5), cv::Point(image.cols - 5, image.rows - 5), cv::Scalar(255, 255, 255), 3);
cv::rectangle(image, cv::Point(image.cols / 2 - 10, image.rows / 2 - 10), cv::Point(image.cols / 2 + 10, image.rows / 2 + 10), cv::Scalar(1, 1, 1), 10);
cv::namedWindow("Image with marker");
cv::imshow("Image with marker", image);
//์›Œํ„ฐ์‰๋“œ ํ‘œ์‹œ
cv::namedWindow("Watershed");
cv::imshow("Watershed", segmenter.getWatersheds());
cv::waitKey();
return 0;
}
================== watershedSegmentation.h ==================
#if !defined WATERSHS
#define WATERSHS
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
class WatershedSegmenter
{
private:
cv::Mat markers;
public:
void setMarkers(const cv::Mat& markerImage)
{
//์ •์ˆ˜ํ˜• ์˜์ƒ์œผ๋กœ ๋ณ€ํ™˜
markerImage.convertTo(markers, CV_32S);
}
cv::Mat process(const cv::Mat &image)
{
//์›Œํ„ฐ์‰๋“œ ์ ์šฉ
cv::watershed(image, markers);
return markers;
}
//๊ฒฐ๊ณผ๋ฅผ ์˜์ƒ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜
cv::Mat getSegmentation()
{
cv::Mat tmp;
// 255๋ณด๋‹ค ๋†’์€ ๋ ˆ์ด๋ธ”์„ ๊ฐ–๋Š” ๋ชจ๋“  ๋ถ„ํ• ์— 255๊ฐ’์„ ํ• ๋‹น
markers.convertTo(tmp, CV_8U);
return tmp;
}
//์›Œํ„ฐ์‰๋“œ๋ฅผ ์˜์ƒ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜
cv::Mat getWatersheds()
{
cv::Mat tmp;
//๋ณ€ํ™˜ํ•˜๊ธฐ ์ „์— ๊ฐ ํ™”์†Œ p๋ฅผ 255*p+255๋กœ ๋ฐ”๊ฟˆ
markers.convertTo(tmp, CV_8U, 255, 255);
return tmp;
}
};
#endif
<์ฝ”๋“œ 3 - MSER๋ฅผ ์ด์šฉํ•ด ๋‘๋“œ๋Ÿฌ์ง„ ์˜์—ญ ์ถ”์ถœ>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/features2d.hpp>
#include <vector>
int main()
{
//์ž…๋ ฅ ์˜์ƒ ์ฝ๊ธฐ
cv::Mat image = cv::imread("../images/building.jpg", 0);
if (image.empty()) return 0;
//์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Image");
cv::imshow("Image", image);
//๊ธฐ๋ณธ MSER ๊ฒ€์ถœ๊ธฐ
cv::Ptr<cv::MSER> ptrMSER = cv::MSER::create(5, //์ง€์—ญ์„ ๊ฒ€์ถœํ•˜๊ธฐ ์œ„ํ•œ ๋ธํƒ€ ๊ฐ’
200, //์ตœ์†Œ ํ—ˆ์šฉ ๋ฉด์ 
2000); //์ตœ๋Œ€ ํ—ˆ์šฉ ๋ฉด์ 
//์  ์ง‘ํ•ฉ์˜ ๋ฐฑํ„ฐ
std::vector<std::vector<cv::Point> > points;
//์ง์‚ฌ๊ฐํ˜•์˜ ๋ฐฑํ„ฐ
std::vector<cv::Rect> rects;
//MSER ํŠน์ง• ๊ฒ€์ถœ
ptrMSER->detectRegions(image, points, rects);
std::cout << points.size() << " MSERs detected" << std::endl;
//ํฐ์ƒ‰ ์˜์ƒ ์ƒ์„ฑ
cv::Mat output(image.size(), CV_8UC3);
output = cv::Scalar(255, 255, 255);
//OpenCV ๋‚œ์ˆ˜ ๋ฐœ์ƒ๊ธฐ(random number generator)
cv::RNG rng;
//MSER์˜ ์ƒ‰์˜์—ญ ํ‘œ์‹œ
//๊ฐ๊ฐ ๊ฒ€์ถœ๋œ ํŠน์ง•์— ๋Œ€ํ•ด ๊ฐ€์žฅ ํฐ MSER๋ถ€ํ„ฐ ์—ญ์ˆœ์„œ๋กœ ํ‘œ์‹œ
for (std::vector<std::vector<cv::Point>>::reverse_iterator it = points.rbegin(); it != points.rend(); ++it)
{
//์ž„์˜ ์ƒ‰ ์ƒ์„ฑ
cv::Vec3b c(rng.uniform(0, 254),
rng.uniform(0, 254),
rng.uniform(0, 254));
std::cout << "MSER size= " << it->size() << std::endl;
//MSER ์ง‘ํ•ฉ์˜ ๊ฐ ์ ์— ๋Œ€ํ•ด
for (std::vector<cv::Point>::iterator itPts = it->begin(); itPts != it->end(); ++itPts)
{
//MSER ํ™”์†Œ๋“ค์„ ๋ฎ์–ด ์“ฐ์ง€ ์•Š์Œ
if (output.at<cv::Vec3b>(*itPts)[0] == 255)
{
output.at<cv::Vec3b>(*itPts) = c;
}
}
}
cv::namedWindow("MSER point sets");
cv::imshow("MSER point sets",output);
cv::imwrite("mser.bmp", output);
//์‚ฌ๊ฐํ˜• MSER๋ฅผ ์ถ”์ถœํ•ด ํ‘œ์‹œ
std::vector<cv::Rect>::iterator itr = rects.begin();
std::vector<std::vector<cv::Point>>::iterator itp = points.begin();
for (; itr != rects.end(); ++itr, ++itp)
{
//๋น„์œจ ํŒ์ •๋ฒ•(ratio test)
if (static_cast<double>(itp->size()) / itr->area() > 0.6)
cv::rectangle(image, *itr, cv::Scalar(255), 2);
}
//๊ฒฐ๊ณผ ์˜์ƒ์„ ํ‘œ์‹œ
cv::namedWindow("Rectangular MSERs");
cv::imshow("Rectangular MSERs", image);
//์ž…๋ ฅ ์˜์ƒ ๋‹ค์‹œ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
image = cv::imread("../images/building.jpg", 0);
if (image.empty()) return 0;
//MSER๋ฅผ ์ถ”์ถœํ•œ ํ›„ ํƒ€์›์œผ๋กœ ํ‘œ์‹œ
for (std::vector<std::vector<cv::Point>>::iterator it = points.begin(); it != points.end(); ++it)
{
//MSER ์ง‘ํ•ฉ์˜ ๊ฐ ์ ์— ๋Œ€ํ•ด
for (std::vector<cv::Point>::iterator itPts = it->begin(); itPts != it->end(); ++itPts)
{
//๊ฒฝ๊ณ„ ์‚ฌ๊ฐํ˜• ์ถ”์ถœ
cv::RotatedRect rr = cv::minAreaRect(*it);
//ํƒ€์›์ด ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธ
if (rr.size.width / rr.size.height > 0.6 || rr.size.height / rr.size.width < 1.6)
cv::ellipse(image, rr, cv::Scalar(255), 2);
}
}
//์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("MSER ellipses");
cv::imshow("MSER ellipses", image);
cv::waitKey();
return 0;
}
6. ์˜์ƒ ํ•„ํ„ฐ๋ง[Filtering the Images]
1) ํ•„ํ„ฐ๋ง(filtering)์€ ์‹ ํ˜ธ์ฒ˜๋ฆฌ์™€ ์˜์ƒ์ฒ˜๋ฆฌ์˜ ๊ธฐ๋ณธ ์ž‘์—… ์ค‘์— ํ•˜๋‚˜์ด๋ฉฐ, ์ฃผ์–ด์ง„ ์‘์šฉ์˜ ๋งฅ๋ฝ์—์„œ ์ค‘์š”ํ•œ ์ •๋ณด ์ „๋‹ฌ๋กœ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ๋Š” ์˜์ƒ์˜ ์–ด๋–ค ์ธก๋ฉด์„ ์„ ํƒ์ ์œผ๋กœ ์ถ”์ถœํ•˜๋Š” ๋ฐ ๋ชฉ์ ์ด ์žˆ๋‹ค.
- ํ•„ํ„ฐ๋ง์€ ์˜์ƒ์˜ ์žก์Œ์„ ์ œ๊ฑฐํ•˜๊ณ , ํฅ๋ฏธ๋กœ์šด ์‹œ๊ฐ์  ํŠน์ง•์„ ์ถ”์ถœํ•˜๋ฉฐ, ์˜์ƒ ์žฌ์ƒ˜ํ”Œ๋ง(ํฌ๊ธฐ์กฐ์ •or ํ™”์†Œ๊ฐ’ ๋ณ€ํ™˜)์ด ๊ฐ€๋Šฅํ•ด์ง€๋Š” ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.
- ํ•„ํ„ฐ๋ง์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์‹ ํ˜ธ ์‹œ์Šคํ…œ(Signal and Systems)์ด๋ก ์˜ ๋ฟŒ๋ฆฌ์— ๋‘”๋‹ค.
- ์ฃผํŒŒ์ˆ˜ ์˜์—ญ ๋ถ„์„(Frequency domain analysis)๋ž€, ๋ช…๋„์˜ ๋ณ€ํ™”๊ฐ€ ๊ธ‰๊ฒฉํ•˜๋ฉด ๋†’์€ ์ฃผํŒŒ์ˆ˜๋ผ๊ณ  ํ•˜๋ฉฐ, ๋ช…๋„์˜ ๋ณ€ํ™”๊ฐ€ ๋А๋ฆฌ๊ฑฐ๋‚˜ ๊ฑฐ์˜์—†์œผ๋ฉด ๋‚ฎ์€ ์ฃผํŒŒ์ˆ˜, ์˜์ƒ์—์„œ ๋ณ€ํ™”์˜ ์ฃผ๊ธฐ๋ฅผ ๊ด€์ฐฐํ•˜๋Š” ๊ฒƒ์ด
์ฃผํŒŒ์ˆ˜ ์˜์—ญ(frequency domain), ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ๋ชป๋ณด๋Š” ๋ณ€ํ™˜๋œ ์˜์ƒ ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ๋ถ„ํฌ๋ฅผ ๊ด€์ฐฐํ•ด ์˜์ƒ์„ ํŠน์„ฑํ™”ํ•œ ๊ฒƒ์€ ๊ณต๊ฐ„ ์˜์—ญ(spatial domain)์ด๋ผ๊ณ  ํ•œ๋‹ค.(์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์˜์ƒ)
- ์ฃผํŒŒ์ˆ˜ ์˜์—ญ์€ ์ˆ˜์ง ์ฃผํŒŒ์ˆ˜(์ˆ˜์ง ๋ฐฉํ–ฅ์—์„œ ๋ณ€ํ™”)์™€ ์ˆ˜ํ‰ ์ฃผํŒŒ์ˆ˜(์ˆ˜ํ‰ ๋ฐฉํ–ฅ์—์„œ ๋ณ€ํ™”)๊ฐ€ ์žˆ๋‹ค.
- ์ €์ฃผํŒŒ ํ†ต๊ณผ ํ•„ํ„ฐ(low-pass filter) ๊ณ ์ฃผํŒŒ ์„ฑ๋ถ„์„ ์ œ๊ฑฐํ•˜๋Š” ํ•„ํ„ฐ, ๊ณ ์ฃผํŒŒ ํ†ต๊ณผ ํ•„ํ„ฐ(high-pass filter) ์ €์ฃผํŒŒ ์„ฑ๋ถ„์„ ์ œ๊ฑฐํ•˜๋Š” ํ•„ํ„ฐ
- ์ €์ฃผํŒŒ ํ†ต๊ณผ ํ•„ํ„ฐ๋ฅผ ๋‹ฌ์„ฑํ•˜๋Š” ํ•œ ๊ฐ€์ง€ ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์€ ๊ฐ ํ™”์†Œ๋ฅผ ์ฃผ๋ณ€์— ์žˆ๋Š” ํ™”์†Œ์˜ ํ‰๊ท  ๊ฐ’์œผ๋กœ ๋Œ€์น˜ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ธ‰๊ฒฉํ•œ ๋ช…๋„ ๋ณ€ํ™”๊ฐ€ ๋ถ€๋“œ๋Ÿฌ์›Œ ์ง„๋‹ค.
- blur()ํ•จ์ˆ˜, ๊ฐ€์šฐ์‹œ์•ˆ(์ข… ๋ชจ์–‘ ํ•จ์ˆ˜) ๋ธ”๋Ÿฌํ•จ์ˆ˜(gaussianblur) ๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌ๋Š” ๊ฐ€๊นŒ์ด ์œ„์น˜ํ•œ ํ™”์†Œ์— ๋” ๋งŽ์€ ์ค‘์š”์„ฑ(๊ฐ€์ค‘์น˜)์„ ๋ถ€์—ฌํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. ๋ณดํ†ต boxํ˜•์ด๊ณ  ์ด๋Ÿฐ ๊ฐ’์ด ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ ์„ ํ˜•์ด๋ผ๊ณ  ํ•œ๋‹ค.
- boxfilter๋Š” 1๋กœ๋งŒ ๋งŒ๋“ค์–ด์ง„ ์ •์‚ฌ๊ฐํ˜• ์ปค๋„์ด๊ณ  blur๋Š” 1/n์œผ๋กœ ๊ณ„์ˆ˜๋กœ ๋‚˜๋ˆˆ๋‹ค. ์„ ํ˜•ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜๋ฉด ์ปค๋„์„ ์˜์ƒ์˜ ๊ฐ ํ™”์†Œ์— ๊ฑธ์ณ ์ด๋™ํ•˜๋ฉด์„œ ๋Œ€์‘ํ•˜๋Š” ๊ฐ ํ™”์†Œ์— ์—ฐ๊ณ„๋˜๋Š” ๊ฐ€์ค‘์น˜๋ฅผ ๊ณฑํ•˜๋Š”๋ฐ ์ˆ˜ํ•™์ ์œผ๋กœ ์ด๋Ÿฐ ์ž‘์—…์„ ํšŒ์„ (convolution)์ด๋ผ๊ณ  ํ•œ๋‹ค.
- ๊ฐ€์šฐ์‹œ์•ˆ ๊ณ„์ˆ˜๋Š” 1๋ณด๋‹ค ํฌ๋ฉด ๊ฐ€์ค‘์น˜๊ฐ€ ๋‚ฎ์•„์ง€๋ฉฐ, ์ž‘์œผ๋ฉด ๊ฐ€์ค‘์น˜๊ฐ€ ์ปค์ง„๋‹ค.
- ๋…ธ์ด์ฆˆ๊ฐ€ ์‹ฌํ•œ๊ฒฝ์šฐ Median Filter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งค์šฐ ํšจ๊ณผ์ ์ด๋‹ค.
- 1D๋กœ ๋ถ„๋ฆฌํ•ด ํ•„ํ„ฐ๋ง ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, cv::sepFilter2D()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. cv::filter2D()ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ํ•œ๋ฒˆ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
- ์ค‘๊ฐ„๊ฐ’ ํ•„ํ„ฐ medianblur(๋ฏธ๋””์•ˆ๋ธ”๋Ÿฌ)๋Š” ์žกํ‹ฐ์ œ๊ฑฐ์— ํšจ๊ณผ์ ์ธ ๋ธ”๋Ÿฌ๋‹ค. ํ”ฝ์…€์„ ๋ญ‰๊ฐ ๋‹ค. ๋‹ค๋ฅธ ํ•„ํ„ฐ์™€ ๋‹ฌ๋ฆฌ ๋น„์„ ํ˜•์ด๋‹ค. ์—์ง€์˜ ์„ ๋ช…๋„๋ฅผ ๋ณด์กดํ•˜์ง€๋งŒ, ๊ท ๋“ฑํ•œ ์˜์—ญ์— ์žˆ๋Š” ์งˆ๊ฐ์„ ์ง€์šฐ๋Š” ๋‹จ์ ๋„ ์žˆ๋‹ค. ์›๋ฆฌ๋Š” ํ”ฝ์…€์„ ์ง‘ํ•ฉํ™”ํ•ด ๊ทธ ์ค‘ ์ค‘๊ฐ„๊ฐ’์œผ๋กœ ๋Œ€์ฒดํ•˜๋Š” ๋ฐฉ์‹์ž„.
2) ์žฌ์ƒ˜ํ”Œ๋ง - ์˜์ƒ์˜ ํฌ๊ธฐ๋ฅผ ์ถ•์†Œํ•˜๋Š” ๊ณผ์ •์€ ๋‹ค์šด์ƒ˜ํ”Œ๋ง, ํฌ๊ธฐ๋ฅผ ํ™•๋Œ€ํ•˜๋Š” ๊ณผ์ •์€ ์—…์ƒ˜ํ”Œ๋ง์ด๋ผ๊ณ  ํ•œ๋‹ค. ์˜์ƒ์˜ ์‹œ๊ฐ์  ํ’ˆ์งˆ์„ ์ตœ๋Œ€ํ•œ ๋ณด์กดํ•ด์•ผํ•œ๋‹ค.
์ถ•์†Œ์‹œ์— ์˜ˆ๋ฅผ๋“ค์–ด 4ํ–‰๊ณผ 4์—ด๋งˆ๋‹ค 1๋กœ ์ค„์—ฌ ์›๋ž˜์˜ ํฌ๊ธฐ๋ฅผ 4๋ฐฐ๋กœ ์ถ•์†Œํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ํ’ˆ์งˆ์ด ๋–จ์–ด์ง€๊ณ  ๊ณ„๋‹จ๋ชจ์–‘(์—์ผ๋ฆฌ์–ด์‹ฑaliasing)์ด ๋‚˜ํƒ€๋‚œ๋‹ค. ๋”ฐ๋ผ์„œ ์ถ•์†Œ ์‹œ ๊ณ ์ฃผํŒŒ ์„ฑ๋ถ„์„ ์ œ๊ฑฐํ•ด์•ผํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์ถ•์†Œ์ „์— ์ €์ฃผํŒŒ ํ†ต๊ณผ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
์—ฌ๊ธฐ์„œ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ด๋ก ์€ ๋‚˜์ดํ€ด์ŠคํŠธ-์ƒˆ๋„Œ ์ด๋ก ์ธ๋ฐ ์˜์ƒ์„ 2๋ฐฐ๋กœ ๋‹ค์šด์ƒ˜ํ”Œ๋งํ–ˆ์„ ๋•Œ ํ‘œํ˜„ ๊ฐ€๋Šฅํ•œ ์ฃผํŒŒ์ˆ˜์˜ ๋Œ€์—ญํญ์ด 2๋ฐฐ๋กœ ์ถ•์†Œ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์ž…์ฆํ•œ๋‹ค.
- OpenCV์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์žฌ์ƒ˜ํ”Œ๋ง ํ•จ์ˆ˜๋กœ cv::pyrDown / cv::pyrUp ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค. ์˜์ƒ์„ ๋‘๋ฐฐ๋กœ ์ถ•์†Œํ•˜๊ฑฐ๋‚˜ ํ™•๋Œ€ํ•˜๋Š” ํ•จ์ˆ˜๋กœ ๊ทธ ์ „์— 5*5 ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ(์ €์ฃผํŒŒ ํ†ต๊ณผ ํ•„ํ„ฐ)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
ํ™•๋Œ€์‹œ์—๋Š” ๋จผ์ € ํ™•๋Œ€(0์„ ์‚ฝ์ž…ํ•ด ์—…์ƒ˜ํ”Œ๋ง) ํ›„ 5*5 ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ๋ฅผ ํ™•๋Œ€ํ•œ ์˜์ƒ์— ์ ์šฉํ•œ๋‹ค.(ํ™•๋Œ€์‹œ ๋˜ํ•œ ๊ณ„์ˆ˜์— 4๋ฅผ ๊ณฑํ•œ๋‹ค.) ์ฃผ๋กœ ์˜์ƒ ํ”ผ๋ผ๋ฏธ๋“œ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.
- ๊ฒฐ๊ณผ์˜์ƒ์„ ์›ํ•˜๋Š” ํฌ๊ธฐ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ๋ฐ˜์ ์ธ cv::resize ํ•จ์ˆ˜๋„ ์žˆ๋‹ค. ๋งˆ์ง€๋ง‰ ์ธ์ž๋Š” ์žฌ์ƒ˜ํ”Œ๋ง ์ฒ˜๋ฆฌ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ณด๊ฐ„๋ฐฉ๋ฒ•์„ ์„ ํƒํ•œ๋‹ค.
3) ๋ณด๊ฐ„ - ๋ณด๊ฐ„์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•์€ ์ตœ๊ทผ์ ‘ ์ด์›ƒ ์ „๋žต(nearest neighbor strategy)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ๋จผ์ € ์™ผ์ชฝ ์˜ค๋ฅธ์ชฝ ์ˆ˜์ง์œผ๋กœ ํ™”์†Œ๊ฐ’์„ ๋ณด๊ฐ„, ๊ทธ ํ›„ ์›ํ•˜๋Š” ์œ„์น˜์—์„œ ์ˆ˜ํ‰์œผ๋กœ ๋ณด๊ฐ„.
๋‹ค๋ฅธ ๋ณด๊ฐ„๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์–‘์„ ํ˜• ๋ณด๊ฐ„๋ฒ•(bilinear interpolation) - ๊ธฐ๋ณธ cv::resize์˜ ๋ฐฉ๋ฒ•
๊ณ ๋“ฑ์ฐจ์ˆ˜ ๋ณด๊ฐ„๋ฒ•(bicubic interpolation)- ์šฐ์ˆ˜ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๋ณด๊ฐ„๋ฒ•. 4x4ํ™”์†Œ์˜ ์ด์›ƒ์„ ๊ณ ๋ คํ•˜๊ณ  ์ž…๋ฐฉ ์กฐ๊ฑด ๊ณ„์‚ฐ์„ ์˜๋ฏธํ•˜๊ธฐ์— ๋А๋ฆฌ๋‹ค.
4) ์—์ง€ ๊ฒ€์ถœ(๋ฐฉํ–ฅ์„ฑ ํ•„ํ„ฐ) - ์˜์ƒ์˜ ๊ณ ์ฃผํŒŒ ๋‚ด์šฉ์„ ์ฆํญํ•ด์„œ(๊ณ ์ฃผํŒŒ ํ†ต๊ณผ ํ•„ํ„ฐ)์˜์ƒ์˜ ์—์ง€ ๊ฒ€์ถœ(Edge Detection)์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ•„ํ„ฐ๋Š” ์†Œ๋ฒจ(Sobel)ํ•„ํ„ฐ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๋ฐ, ๋ฐฉํ–ฅ์„ฑ ํ•„ํ„ฐ๋ผ๊ณ ๋„ ํ•œ๋‹ค. ๊ทธ ์ด์œ ๋Š” ์ˆ˜ํ‰์ด๋‚˜ ์ˆ˜์ง ์˜์ƒ ์ฃผํŒŒ์ˆ˜์—๋งŒ ์˜ํ–ฅ์„ ์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
-1 0 1
-2 0 -2
-1 0 1
-1 -2 -1
0 0 0
1 2 1
cv::Sobel() ๊ฐ€๋กœ ์„ธ๋กœ๋ฅผ ์–ป์–ด norm์„ ์–ป๊ธฐ ์œ„ํ•ด ์กฐํ•ฉํ•œ๋‹ค. ์†Œ๋ฒจ ์—ฐ์‚ฐ์ž์˜ ์ปค๋„์€ ์–‘์ˆ˜ ๊ฐ’๊ณผ ์Œ์ˆ˜ ๊ฐ’์„ ํฌํ•จํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์†Œ๋ฒจ ํ•„ํ„ฐ์˜ ๊ฒฐ๊ณผ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ 16๋น„ํŠธ์˜ ๋ถ€ํ˜ธ ์žˆ๋Š” ์ •์ˆ˜ํ˜• ์˜์ƒ์œผ๋กœ ๊ณ„์‚ฐ๋œ๋‹ค.
์˜์ƒ์„ 2์ฐจ์› ํ•จ์ˆ˜๋กœ ๋ฐ”๋ผ๋ณธ๋‹ค๋ฉด ์†Œ๋ฒจ ์—ฐ์‚ฐ์ž๋Š” ์ˆ˜ํ‰ ๋ฐฉํ–ฅ๊ณผ ์ˆ˜์ง ๋ฐฉํ–ฅ์—์„œ ์˜์ƒ์˜ ๋ณ€ํ™”๋ฅผ ์ธก์ •ํ•˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ๋‹ค. ์ˆ˜ํ•™์  ์šฉ์–ด๋กœ๋Š” ์ด ์ธก์ •์„ ๊ธฐ์šธ๊ธฐ(gradient)๋ผ๊ณ  ๋ถ€๋ฅด๋ฉฐ, ๋‘ ์ง๊ต ๋ฐฉํ–ฅ์—์„œ ํ•จ์ˆ˜์˜ 1์ฐจ ๋ฏธ๋ถ„์œผ๋กœ๋ถ€ํ„ฐ ๋งŒ๋“ค์–ด์ง„ 2D๋ฒกํ„ฐ๋กœ ์ •์˜๋œ๋‹ค.
์†Œ๋ฒจ ์—ฐ์‚ฐ์ž๋Š” ์ˆ˜ํ‰, ์ˆ˜์ง ๋ฐฉํ–ฅ์—์„œ ํ™”์†Œ ์ฐจ์ด์— ์˜ํ•œ ์˜์ƒ ๊ธฐ์šธ๊ธฐ์˜ ๊ทผ์‚ฌ์น˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ๊ธฐ์šธ๊ธฐ ๋ฒกํ„ฐ์˜ ๋†ˆ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์œ ํด๋ฆฌ๋””์•ˆ ๋†ˆ(L2 norm)์œผ๋กœ ๊ณ„์‚ฐ๋œ๋‹ค.
๋‹ค๋งŒ, ์˜์ƒ์ฒ˜๋ฆฌ์—์„œ๋Š” ์ ˆ๋Œ€ ๊ฐ’์˜ ํ•ฉ์œผ๋กœ ๋†ˆ์„ ์ข…์ข… ๊ณ„์‚ฐํ•œ๋‹ค. ๊ทธ๊ฑธ L1 ๋†ˆ์ด๋ผ๊ณ  ํ•˜๋ฉฐ L2 ๋†ˆ์— ๊ฐ€๊นŒ์šด ๊ฐ’์„ ์ œ๊ณตํ•˜์ง€๋งŒ ๊ณ„์‚ฐ ๋น„์šฉ์ด ๋” ์ ๊ฒŒ ๋“ ๋‹ค.
๋†ˆ๊ณผ ๊ฐ๋„๊ฐ€ ๋‘˜ ๋‹ค ํ•„์š”ํ•  ์‹œ์—๋Š” L2 ์†Œ๋ฒจ์„ ๋ถ€๋™์†Œ์ˆ˜์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜๊ณ , cartToPolar() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ๋‘๊ฐœ ๋‹ค ๊ตฌํ•ด์•ผํ•œ๋‹ค.
๊ธฐ์šธ๊ธฐ ๊ฐ•๋„๋ฅผ ๊ฒฝ๊ณ„ํ™”ํ•ด ์ด์ง„ ์—์ง€ ๋งต์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ํžˆ์Šคํ…Œ๋ฆฌ์‹œ์Šค ๊ฒฝ๊ณ„ํ™” ๊ฐœ๋…์„ ์‚ฌ์šฉํ•˜๋ฉด ์ตœ์ ์˜ ๊ฒฝ๊ณ„ํ™”๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
๊ธฐ์šธ๊ธฐ๋ฅผ ์ถ”์ •ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ๊ธฐ์šธ๊ธฐ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
1. Prewitt ๋ฐฉํ–ฅ์„ฑ์ด ์‚ด์ง ์•ฝํ•œ ์—ฐ์‚ฐ์ž
-1 0 1
-1 0 1
-1 0 1
-1 -1 -1
0 0 0
1 1 1
2. Roberts ๊ฐ„๋‹จํ•œ, ๋‹จ์ˆœํ•œ 2x2 ์ปค๋„
1 0
0 -1
0 1
-1 0
3. Scharr ๊ธฐ์šธ๊ธฐ ๋ฐฉํ–ฅ์„ ๋ณด๋‹ค ์ •ํ™•ํ•˜๊ฒŒ ์ถ”์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
-3 0 3
-10 0 10
-3 0 3
-3-10 -3
0 0 0
3 10 3
cv::Sobel(image,sobelX,CV_16S,1,0,CV_SCHARR) or cv::Scharr(image,scharrX,CV_16S,1,0,3) ์ด๋Ÿฐ์‹์œผ๋กœ ์ ์šฉ
+ ๊ฐ€์šฐ์‹œ์•ˆ ๋ฏธ๋ถ„ 7x7 ์ฒ˜๋Ÿผ ์ปค๋„์˜ ํฌ๊ธฐ๋ฅผ ํ‚ค์›Œ sobel๋ฅผ ์ ์šฉํ•˜๋ฉด, ๊ณ ์ฃผํŒŒ์™€ ์ €์ฃผํŒŒ๊ฐ€ ๋‘˜๋‹ค ์ ์šฉ๋˜์–ด ๋Œ€์—ญ ํ†ต๊ณผ ํ•„ํ„ฐ๊ฐ€ ๋œ๋‹ค. ์ด๋Ÿฌ๋ฉด ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐํšจ๊ณผ์™€ ์—์ง€ ๊ฒ€์ถœ์ด ๋‘˜๋‹ค ์ ์šฉ๋˜๋Š” ๊ฒƒ.
5) ๋ผํ”Œ๋ผ์‹œ์•ˆ(Laplacian) - ์˜์ƒ ๋ฏธ๋ถ„ ๊ณ„์‚ฐ์— ๊ธฐ๋ฐ˜์„ ๋‘๋Š” ๋‹ค๋ฅธ ๊ณ ์ฃผํŒŒ ์„ ํ˜• ํ•„ํ„ฐ๋‹ค. ์˜์ƒ ํ•จ์ˆ˜์˜ ๊ณก๋ฅ curvature์„ ์ธก์ •ํ•˜๊ธฐ ์œ„ํ•ด 2์ฐจ ๋ฏธ๋ถ„์„ ๊ณ„์‚ฐํ•œ๋‹ค.
0 1 0
1 -4 1
0 1 0
cv::Laplacian()ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์ด ํ•จ์ˆ˜๋Š” cv::getDerivKernels() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ ์šฉ๋œ๋‹ค. ๋ผํ”Œ๋ผ์‹œ์•ˆ์€ 2์ฐจ ๋ฏธ๋ถ„์ด๋‹ค. ๋ผํ”Œ๋ผ์‹œ์•ˆ์€ ์žก์Œ์— ๋งค์šฐ ๋ฏผ๊ฐํ•˜๋‹ค. ๊ณ ์ฃผํŒŒ ํ†ต๊ณผ ํ•„ํ„ฐ.
๋ผํ”Œ๋ผ์‹œ์•ˆ์˜ ์˜๊ต์ฐจ(์„œ๋กœ ๋‹ค๋ฅธ ๋ถ€ํ˜ธ์ธ ํ™”์†Œ ์‚ฌ์ด์— ์œ„์น˜)๋ฅผ ํ†ตํ•ด ์˜์ƒ ์—์ง€๋ฅผ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ผํ”Œ๋ผ์‹œ์•ˆ์˜ ์˜๊ต์ฐจ๋Š” ๋ชจ๋“  ์—์ง€๋ฅผ ๊ฒ€์ถœํ•œ๋‹ค. ๊ฐ•ํ•œ ์—์ง€์™€ ์•ฝํ•œ ์—์ง€ ์‚ฌ์ด๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†๋‹ค.
๋ผํ”Œ๋ผ์‹œ์•ˆ์„ ์‚ฌ์šฉํ•ด ์˜์ƒ์˜ ๋ช…์•” ๋Œ€๋น„ ํ–ฅ์ƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. - ์› ์˜์ƒ์— ๋ผํ”Œ๋ผ์‹œ์•ˆ์„ ๋บŒ์œผ๋กœ์จ ์˜์ƒ์˜ ๋ช…์•” ๋Œ€๋น„๋ฅผ ํ–ฅ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
1์— ๋ผํ”Œ๋ผ์‹œ์•ˆ ์ปค๋„์„ ๋บ€ ๊ฒƒ๊ณผ ๋™์ผํ•˜๋‹ค.
6) ๊ฐ€์šฐ์‹œ์•ˆ ์ฐจ๋ถ„(Difference of Gaussians: DoG) - ๊ฐ€์šฐ์‹œ์•ˆ ๋‹ค๋ฅธ ๊ณ„์ˆ˜๋กœ ๊ตฌํ•œ ๊ฐ’์˜ ์ฐจ, DoG์˜ ์˜๊ต์ฐจ๋ฅผ ๊ตฌํ•˜๋ฉด ๋” ์ •ํ™•ํ•˜๊ฒŒ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค. scale-space ํ‘œํ˜„์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
DoG๋Š” LoG(Laplacian of Gaussian)ํ•„ํ„ฐ์˜ ํ›Œ๋ฅญํ•œ ๊ทผ์‚ฌํ™”๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.
<์ฝ”๋“œ 1 - ํ•„ํ„ฐ - ์ €์ฃผํŒŒ ํ†ต๊ณผ ํ•„ํ„ฐ, ๋‹ค์šด์ƒ˜ํ”Œ๋ง, ์ค‘๊ฐ„ ๊ฐ’ ํ•„ํ„ฐ>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
int main()
{
//์ž…๋ ฅ ์˜์ƒ ์ฝ๊ธฐ
cv::Mat image = cv::imread("../images/boldt.jpg", 0);
if (!image.data) return 0;
//์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Original Image");
cv::imshow("Original Image", image);
//ํ‰๊ท ๊ฐ’ํ•„ํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์˜์ƒ์„ ํ๋ฆฌ๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ
cv::Mat result;
cv::blur(image, result, cv::Size(5, 5));
//ํ๋ฆฌ๊ฒŒํ•œ ์˜์ƒ์„ ํ‘œ์‹œ
cv::namedWindow("Mean filtered Image");
cv::imshow("Mean filtered Image", result);
//9x9 ํ‰๊ท ๊ฐ’ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ํ๋ฆฌ๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ
cv::blur(image, result, cv::Size(9, 9));
//ํ๋ฆฌ๊ฒŒํ•œ ์˜์ƒ์„ ํ‘œ์‹œ
cv::namedWindow("Mean filtered Image (9x9)");
cv::imshow("Mean filtered Image (9x9)", result);
//๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌ ์˜์ƒ
cv::GaussianBlur(image, result,
cv::Size(5, 5), //ํ•„ํ„ฐ์˜ ํฌ๊ธฐ
1.5); //๊ฐ€์šฐ์‹œ์•ˆ์˜ ๋ชจ์–‘์„ ์กฐ์ •ํ•˜๋Š” ๊ณ„์ˆ˜
//๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌ๋œ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Gaussian filtered Image");
cv::imshow("Gaussian filtered Image", result);
cv::GaussianBlur(image, result, cv::Size(9, 9), 1.7);
//๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌ (9x9)๋œ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Gaussian filtered Image (9x9)");
cv::imshow("Gaussian filtered Image (9x9)", result);
//๊ฐ€์šฐ์‹œ์•ˆ ์ปค๋„ (1.5) ์ ์šฉํ•˜๊ธฐ
cv::Mat gauss = cv::getGaussianKernel(9, 1.5, CV_32F);
//์ปค๋„ ๊ฐ’ ํ‘œ์‹œ
cv::Mat_<float>::const_iterator it = gauss.begin<float>();
cv::Mat_<float>::const_iterator itend = gauss.end<float>();
std::cout << "1.5 = [";
for (; it != itend; ++it)
{
std::cout << *it << " ";
}
std::cout << "]" << std::endl;
//๊ฐ€์šฐ์‹œ์•ˆ ์ปค๋„ (0.5) ์ ์šฉํ•˜๊ธฐ
gauss = cv::getGaussianKernel(9, 0.5, CV_32F);
//์ปค๋„ ๊ฐ’ ํ‘œ์‹œ
it = gauss.begin<float>();
itend = gauss.end<float>();
std::cout << "0.5 = [";
for (; it != itend; ++it)
{
std::cout << *it << " ";
}
std::cout << "]" << std::endl;
//๊ฐ€์šฐ์‹œ์•ˆ ์ปค๋„ (2.5) ์ ์šฉํ•˜๊ธฐ
gauss = cv::getGaussianKernel(9, 2.5, CV_32F);
//์ปค๋„ ๊ฐ’ ํ‘œ์‹œ
it = gauss.begin<float>();
itend = gauss.end<float>();
std::cout << "2.5 = [";
for (; it != itend; ++it)
{
std::cout << *it << " ";
}
std::cout << "]" << std::endl;
//๊ฐ€์šฐ์‹œ์•ˆ ์ปค๋„ (9 ์š”์†Œ๋“ค) ์ ์šฉํ•˜๊ธฐ
gauss = cv::getGaussianKernel(9, -1, CV_32F);
//์ปค๋„ ๊ฐ’ ํ‘œ์‹œ
it = gauss.begin<float>();
itend = gauss.end<float>();
std::cout << "9 = [";
for (; it != itend; ++it)
{
std::cout << *it << " ";
}
std::cout << "]" << std::endl;
//๋ถ„๋ฆฌ๋œ ์ปค๋„๋กœ (2.5) ์ ์šฉํ•˜๊ธฐ
cv::Mat kx, ky;
cv::getDerivKernels(kx, ky, 2, 2, 7, true);
//์ปค๋„ ๊ฐ’ ํ‘œ์‹œ
cv::Mat_<float>::const_iterator kit = kx.begin<float>();
cv::Mat_<float>::const_iterator kitend = kx.end<float>();
std::cout << "[";
for (; kit != kitend; ++kit)
{
std::cout << *kit << " ";
}
std::cout << "]" << std::endl;
//Salt&Pepper ๋…ธ์ด์ฆˆ ํฌํ•จํ•ด์„œ ์ž…๋ ฅ ์˜์ƒ ์ฝ๊ธฐ
image = cv::imread("../images/salted.bmp", 0);
if (!image.data) return 0;
cv::namedWindow("S&P Image");
cv::imshow("S&P Image", image);
//ํ‰๊ท ๊ฐ’ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์˜์ƒ ๋ธ”๋Ÿฌํšจ๊ณผ ์ฃผ๊ธฐ
cv::blur(image, result, cv::Size(5, 5));
//๋ธ”๋Ÿฌ๋œ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Mean filtered S&P Image");
cv::imshow("Mean filtered S&P Image",result);
//๋ฏธ๋””์•ˆ ๋ธ”๋Ÿฌ ํ•„ํ„ฐ ์ ์šฉ ๋งˆ์ง€๋ง‰ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์ค‘๊ฐ„ ๊ฐ’ ํ•„ํ„ฐ์˜ ํฌ๊ธฐ์ž„
cv::medianBlur(image, result, 5);
//๋ธ”๋Ÿฌ๋œ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Median filtered Image");
cv::imshow("Median filtered Image", result);
//์˜์ƒ์˜ ํฌ๊ธฐ๋ฅผ 4๋ฐฐ ๊ฐ์†Œ (์ž˜๋ชป๋œ ๋ฐฉ๋ฒ•)
image = cv::imread("../images/boldt.jpg", 0);
cv::Mat reduced(image.rows / 4, image.cols / 4, CV_8U);
for (int i = 0; i < reduced.rows; i++)
for (int j = 0; j < reduced.cols; j++)
reduced.at<uchar>(i, j) = image.at<uchar>(i * 4, j * 4);
//์ถ•์†Œ๋œ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Badly reduced Image (aliasing)");
cv::imshow("Badly reduced Image (aliasing)", reduced);
cv::resize(reduced, reduced, cv::Size(), 4, 4, cv::INTER_NEAREST);
//์ถ•์†Œ๋œ(resize ์‚ฌ์šฉํ•œ) ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Badly reduced (resize)");
cv::imshow("Badly reduced (resize)", reduced);
cv::imwrite("badlyreducedimage.bmp", reduced);
//๋จผ์ € ๊ณ ์ฃผํŒŒ ์„ฑ๋ถ„ ์ œ๊ฑฐ
cv::GaussianBlur(image, image, cv::Size(11, 11), 1.75);
//4ํ™”์†Œ๋งˆ๋‹ค 1ํ™”์†Œ๋งŒ ์œ ์ง€
cv::Mat reduced2(image.rows / 4, image.cols / 4, CV_8U);
for (int i = 0; i < reduced2.rows; i++)
for (int j = 0; j < reduced2.cols; j++)
reduced2.at<uchar>(i, j) = image.at<uchar>(i * 4, j * 4);
//์ถ•์†Œ๋œ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Reduced Image, original size");
cv::imshow("Reduced Image, original size", reduced2);
cv::imwrite("reducedimage.bmp", reduced2);
//NN์œผ๋กœ ์žฌ์ƒ˜ํ”Œ๋ง
cv::Mat newImage;
cv::resize(reduced2, newImage, cv::Size(), 4, 4, cv::INTER_NEAREST);
//์ถ•์†Œ๋œ(resize ์‚ฌ์šฉํ•œ) ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Reduced Image (resize)");
cv::imshow("Reduced Image (resize)", newImage);
//bilinear๋กœ ์žฌ์ƒ˜ํ”Œ๋ง
cv::resize(reduced2, newImage, cv::Size(), 4, 4, cv::INTER_LINEAR);
//์ถ•์†Œ๋œ(resize ์‚ฌ์šฉํ•œ) ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Bilinear resizing");
cv::imshow("Bilinear resizing", newImage);
//ํ”ผ๋ผ๋ฏธ๋“œ ์˜์ƒ ์ƒ์„ฑ
cv::Mat pyramid(image.rows, image.cols + image.cols / 2 + image.cols / 4 + image.cols / 8, CV_8U, cv::Scalar(255));
image.copyTo(pyramid(cv::Rect(0, 0, image.cols, image.rows)));
cv::pyrDown(image, reduced); //์˜์ƒ์„ ์ ˆ๋ฐ˜์œผ๋กœ ์ถ•์†Œํ•จ
reduced.copyTo(pyramid(cv::Rect(image.cols, image.rows / 2, image.cols / 2, image.rows / 2)));
cv::pyrDown(reduced, reduced2); //๋˜๋‹ค๋ฅธ ์˜์ƒ์„ ์ ˆ๋ฐ˜์œผ๋กœ ์ถ•์†Œํ•จ
reduced2.copyTo(pyramid(cv::Rect(image.cols + image.cols / 2, image.rows - image.rows / 4, image.cols / 4, image.rows / 4)));
cv::pyrDown(reduced2, reduced); //๋˜๋‹ค๋ฅธ ์˜์ƒ์„ ์ ˆ๋ฐ˜์œผ๋กœ ์ถ•์†Œํ•จ
reduced.copyTo(pyramid(cv::Rect(image.cols + image.cols / 2 + image.cols/4, image.rows - image.rows / 8, image.cols / 8, image.rows / 8)));
//ํ”ผ๋ผ๋ฏธ๋“œ ํ‘œ์‹œ
cv::namedWindow("Pyramid of images");
cv::imshow("Pyramid of images", pyramid);
cv::waitKey();
return 0;
}
<์ฝ”๋“œ 2 - ํ•„ํ„ฐ - ์—์ง€๋ฅผ ๊ฒ€์ถœํ•˜๋Š” ๋ฐฉํ–ฅ์„ฑ ํ•„ํ„ฐ(๊ณ ์ฃผํŒŒ ํ†ต๊ณผ ํ•„ํ„ฐ)์™€ ๋ผํ”Œ๋ผ์‹œ์•ˆ>
#include <iostream>
#include <iomanip>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include "laplacianZC.h"
int main()
{
//์ž…๋ ฅ ์˜์ƒ ์ฝ๊ธฐ
cv::Mat image = cv::imread("../images/boldt.jpg", 0);
if (image.empty()) return 0;
//์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Original Image");
cv::imshow("Original Image", image);
//์†Œ๋ฒจ ๊ฐ€๋กœ(X) ๋ฏธ๋ถ„๊ณ„์‚ฐ
cv::Mat sobelX;
cv::Sobel(image, //์ž…๋ ฅ
sobelX, //๊ฒฐ๊ณผ
CV_8U, //์˜์ƒํƒ€์ž…
1, 0, //์ปค๋„์ง€์ •
3, //์ •๋ฐฉํ–ฅ ์ปค๋„ ํฌ๊ธฐ
0.4, 128); //ํฌ๊ธฐ ์กฐ์ •๊ณผ ์˜คํ”„์…‹
//์†Œ๋ฒจ ๊ฐ€๋กœ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Sobel X Image");
cv::imshow("Sobel X Image", sobelX);
//์†Œ๋ฒจ ์„ธ๋กœ(Y) ๋ฏธ๋ถ„๊ณ„์‚ฐ
cv::Mat sobelY;
cv::Sobel(image, //์ž…๋ ฅ
sobelY, //๊ฒฐ๊ณผ
CV_8U, //์˜์ƒํƒ€์ž…
0, 1, //์ปค๋„์ง€์ •
3, //์ •๋ฐฉํ–ฅ ์ปค๋„ ํฌ๊ธฐ
0.4, 128); //ํฌ๊ธฐ ์กฐ์ •๊ณผ ์˜คํ”„์…‹
//์†Œ๋ฒจ ์„ธ๋กœ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Sobel Y Image");
cv::imshow("Sobel Y Image", sobelY);
//์†Œ๋ฒจ ๋†ˆ ๊ณ„์‚ฐ
cv::Sobel(image, sobelX, CV_16S, 1, 0);
cv::Sobel(image, sobelY, CV_16S, 0, 1);
//L1 ๋†ˆ ๊ณ„์‚ฐ
cv::Mat sobel;
sobel = abs(sobelX) + abs(sobelY);
//์†Œ๋ฒจ ์ตœ์†Ÿ๊ฐ’/์ตœ๋Œ“๊ฐ’ ์ฐพ๊ธฐ
double sobmin, sobmax;
cv::minMaxLoc(sobel, &sobmin, &sobmax);
std::cout << "sobel value range: " << sobmin << " " << sobmax << std::endl;
//์†Œ๋ฒจ ๊ฐ€๋กœ(X) ๋ฏธ๋ถ„ (7x7)
cv::Sobel(image, sobelX, CV_8U, 1, 0, 7, 0.001, 128);
//7x7 ์†Œ๋ฒจ ๊ฐ€๋กœ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Sobel X Image (7x7)");
cv::imshow("Sobel X Image (7x7)", sobelX);
//์ฐฝ ํ™”์†Œ ๊ฐ’๋“ค์„ ์ถœ๋ ฅ
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++)
std::cout << std::setw(5) << static_cast<int>(sobel.at<short>(i+79,j+215)) << " ";
std::cout << std::endl;
}
std::cout << std::endl;
std::cout << std::endl;
std::cout << std::endl;
//8๋น„ํŠธ ์˜์ƒ์œผ๋กœ ๋ณ€ํ™˜
//sobelImage = -alpha*sobel + 255
cv::Mat sobelImage;
sobel.convertTo(sobelImage, CV_8U, -255. / sobmax, 255);
//์†Œ๋ฒจ ๋†ˆ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Sobel Image");
cv::imshow("Sobel Image", sobelImage);
//์†Œ๋ฒจ ๋†ˆ์— ๊ฒฝ๊ณ„ํ™” ์ ์šฉ (๋‚ฎ์€ ๊ฒฝ๊ณ„ํ™” ๊ฐ’)
cv::Mat sobelThresholded;
cv::threshold(sobelImage, sobelThresholded, 225, 255, cv::THRESH_BINARY);
//์ด์ง„ ๊ฒฝ๊ณ„ํ™”ํ•œ ์†Œ๋ฒจ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Binary Sobel Image (low)");
cv::imshow("Binary Sobel Image (low)", sobelThresholded);
//์†Œ๋ฒจ ๋†ˆ์— ๊ฒฝ๊ณ„ํ™” ์ ์šฉ (๋†’์€ ๊ฒฝ๊ณ„ํ™” ๊ฐ’)
cv::threshold(sobelImage, sobelThresholded, 190, 255, cv::THRESH_BINARY);
//์ด์ง„ ๊ฒฝ๊ณ„ํ™”ํ•œ ์†Œ๋ฒจ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Binary Sobel Image (high)");
cv::imshow("Binary Sobel Image (high)", sobelThresholded);
//3x3 ๋ผํ”Œ๋ผ์‹œ์•ˆ ๊ณ„์‚ฐ
cv::Mat laplace;
cv::Laplacian(image, laplace, CV_8U, 1, 1, 128);
//๋ผํ”Œ๋ผ์‹œ์•ˆ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Laplacian Image");
cv::imshow("Laplacian Image", laplace);
int cx(238), cy(90);
int dx(12), dy(12);
//์ž‘์€ ์œˆ๋„์šฐ ์ถ”์ถœ
cv::Mat window(image, cv::Rect(cx, cy, dx, dy));
cv::namedWindow("Image window");
cv::imshow("Image window", window);
cv::imwrite("window.bmp", window);
//LaplacianZC ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด ๋ผํ”Œ๋ผ์‹œ์•ˆ ๊ณ„์‚ฐ
LaplacianZC laplacian;
laplacian.setAperture(7); //7x7 ๋ผํ”Œ๋ผ์‹œ์•ˆ
cv::Mat flap = laplacian.computeLaplacian(image);
//๋ผํ”Œ๋ผ์‹œ์•ˆ์˜ ์ตœ๋Œ€/์ตœ์†Ÿ๊ฐ’ ํ‘œ์‹œ
double lapmin, lapmax;
cv::minMaxLoc(flap, &lapmin, &lapmax);
//7x7 ๋ผํ”Œ๋ผ์‹œ์•ˆ ์˜์ƒ ํ‘œ์‹œ
laplace = laplacian.getLaplacianImage();
cv::namedWindow("Laplacian Image (7x7)");
cv::imshow("Laplacian Image (7x7)", laplace);
//์˜์ƒ ๊ฐ’๋“ค ์ถœ๋ ฅ
std::cout << std::endl;
std::cout << "image values:\n\n";
for (int i = 0; i < dx; i++)
{
for (int j = 0; j < dy; j++)
std::cout << std::setw(5) << static_cast<int>(image.at<uchar>(i + cy, j + cx)) << " ";
std::cout << std::endl;
}
//๋ผํ”Œ๋ผ์‹œ์•ˆ ๊ฐ’๋“ค ์ถœ๋ ฅ
std::cout << "Laplacian value range=[" << lapmin << ", " << lapmax << "]\n";
std::cout << std::endl;
for (int i = 0; i < dx; i++)
{
for (int j = 0; j < dy; j++)
std::cout << std::setw(5) << static_cast<int>(flap.at<float>(i + cy, j + cx)/ 100) << " ";
std::cout << std::endl;
}
std::cout << std::endl;
//์˜๊ต์ฐจ ์ ๋“ค ๊ณ„์‚ฐ๊ณผ ํ‘œ์‹œ
cv::Mat zeros;
zeros = laplacian.getZeroCrossings(flap);
cv::namedWindow("Zero-crossings");
cv::imshow("Zero-crossings", 255 - zeros);
//์œˆ๋„์šฐ ํ™”์†Œ ๊ฐ’์„ ์ถœ๋ ฅ
std::cout << "Zero values:\n\n";
for (int i = 0; i < dx; i++) {
for (int j = 0; j < dy; j++)
std::cout << std::setw(2) << static_cast<int>(zeros.at<uchar>(i + cy, j + cx)) / 255 << " ";
std::cout << std::endl;
}
//๋‹ค์šด์ƒ˜ํ”Œ๋ง๊ณผ ์—…์ƒ˜ํ”Œ๋งํ•œ ์˜์ƒ
cv::Mat reduced, rescaled;
cv::pyrDown(image, reduced);
cv::pyrUp(reduced, rescaled);
//๋ฆฌ์Šค์ผ€์ผํ•œ ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("Rescaled Image");
cv::imshow("Rescaled Image", rescaled);
//๊ฐ€์šฐ์‹œ์•ˆ ํ”ผ๋ผ๋ฏธ๋“œ์˜ ์ฐจ๋ถ„ ๊ณ„์‚ฐ
cv::Mat dog;
cv::subtract(rescaled, image, dog, cv::Mat(), CV_16S);
cv::Mat dogImage;
dog.convertTo(dogImage, CV_8U, 1.0, 128);
//DoG ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("DoG Image (from pyrdown/pyrup)");
cv::imshow("DoG Image (from pyrdown/pyrup)", dogImage);
//๋‘๊ฐœ์˜ ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ ์ ์šฉ
cv::Mat gauss05;
cv::Mat gauss15;
cv::GaussianBlur(image, gauss05, cv::Size(), 0.5);
cv::GaussianBlur(image, gauss15, cv::Size(), 1.5);
//๊ฐ€์šฐ์‹œ์•ˆ ์ฐจ๋ถ„ ๊ณ„์‚ฐ
cv::subtract(gauss15, gauss05, dog, cv::Mat(), CV_16S);
dog.convertTo(dogImage, CV_8U, 2.0, 128);
//DoG ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("DoG Image");
cv::imshow("DoG Image", dogImage);
//๋‘๊ฐœ์˜ ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ ์ ์šฉํ•˜๊ธฐ
cv::Mat gauss20;
cv::GaussianBlur(image, gauss20, cv::Size(), 2.0);
cv::Mat gauss22;
cv::GaussianBlur(image, gauss22, cv::Size(), 2.2);
//๊ฐ€์šฐ์‹œ์•ˆ ์ฐจ๋ถ„ ๊ณ„์‚ฐ
cv::subtract(gauss22, gauss20, dog, cv::Mat(), CV_32F);
dog.convertTo(dogImage, CV_8U, 10.0, 128);
//DoG ์˜์ƒ ํ‘œ์‹œ
cv::namedWindow("DoG Image (2)");
cv::imshow("DoG Image (2)", dogImage);
//DoG์˜ ์˜๊ต์ฐจ ํ‘œ์‹œ
zeros = laplacian.getZeroCrossings(dog);
cv::namedWindow("Zero-crossings of DoG");
cv::imshow("Zero-crossings of DoG", 255 - zeros);
//์˜์ƒ๊ณผ ์˜์ƒ์˜ ์œˆ๋„์šฐ ํ‘œ์‹œ
cv::rectangle(image, cv::Rect(cx, cy, dx, dy), cv::Scalar(255,255,255));
cv::namedWindow("Original Image with window");
cv::imshow("Original Image with window", image);
cv::waitKey();
return 0;
}
============================ laplacianZC.h ============================
#if !defined LAPLACEZC
#define LAPLACEZC
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
class LaplacianZC
{
private:
//๋ผํ”Œ๋ผ์‹œ์•ˆ
cv::Mat laplace;
//๋ผํ”Œ๋ผ์‹œ์•ˆ ์ปค๋„์˜ ๊ตฌ๊ฒฝ ํฌ๊ธฐ
int aperture;
public:
LaplacianZC() : aperture(3) {}
//์ปค๋„์˜ ๊ตฌ๊ฒฝ ํฌ๊ธฐ ์„ค์ •
void setAperture(int a)
{
aperture = a;
}
//์ปค๋„์˜ ๊ตฌ๊ฒฝ ํฌ๊ธฐ ๊ฐ€์ ธ์˜ค๊ธฐ
int getAperture() const
{
return aperture;
}
//๋ผํ”Œ๋ผ์‹œ์•ˆ์„ ๋ถ€๋™์†Œ์ˆ˜์ ์œผ๋กœ ๊ณ„์‚ฐ
cv::Mat computeLaplacian(const cv::Mat& image)
{
//๋ผํ”Œ๋ผ์‹œ์•ˆ ๊ณ„์‚ฐ
cv::Laplacian(image, laplace, CV_32F, aperture);
return laplace;
}
//๋ผํ”Œ๋ผ์‹œ์•ˆ ๊ฒฐ๊ณผ๋ฅผ 8๋น„ํŠธ ์˜์ƒ์œผ๋กœ ์–ป๊ธฐ
//0์€ ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ 128์— ๋Œ€์‘
//scale์„ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฉด ์ตœ๋Œ“๊ฐ’์„ ๋ช…๋„ 255๋กœ ์กฐ์ •
//์ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— computeLaplacian๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•จ
cv::Mat getLaplacianImage(double scale = -1.0)
{
if (scale < 0)
{
double lapmin, lapmax;
cv::minMaxLoc(laplace, &lapmin, &lapmax);
scale = 127 / std::max(-lapmin, lapmax);
}
cv::Mat laplaceImage;
laplace.convertTo(laplaceImage, CV_8U, scale, 128);
return laplaceImage;
}
//์˜๊ต์ฐจ์˜ ์ด์ง„ ์˜์ƒ ์–ป๊ธฐ
//๋ผํ”Œ๋ผ์‹œ์•ˆ ์˜์ƒ์€ CV_32F์ด์–ด์•ผ ํ•จ
cv::Mat getZeroCrossings(cv::Mat laplace)
{
//0์—์„œ ๊ฒฝ๊ณ„ํ™”
//์Œ์ˆ˜ ๊ฐ’์€ ๊ฒ€์€์ƒ‰
//์–‘์ˆ˜ ๊ฐ’์€ ํฐ์ƒ‰
cv::Mat signImage;
cv::threshold(laplace, signImage, 0, 255, cv::THRESH_BINARY);
//+/- ์˜์ƒ์„ CV_8U๋กœ ๋ณ€ํ™˜
cv::Mat binary;
signImage.convertTo(binary, CV_8U);
//+/- ์˜์—ญ์˜ ์ด์ง„ ์˜์ƒ์„ ํŒฝ์ฐฝ
cv::Mat dilated;
cv::dilate(binary, dilated, cv::Mat());
//์˜๊ต์ฐจ ์™ธ๊ฐ์„  ๋ณ€ํ™˜
return dilated - binary;
}
};
#endif
7. ์„ , ์™ธ๊ณฝ์„ , ์„ฑ๋ถ„ ์ถ”์ถœ [Extracting Lines, Contours and Components]
์˜์ƒ์˜ ์˜๋ฏธ์žˆ๋Š” ๋‚ด์šฉ์„ ์ถ”์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋‹ค๋ฃฌ๋‹ค.
1) ์บ๋‹ˆ ์—ฐ์‚ฐ์ž
- ๊ธฐ์กด ์—์ง€ ๊ฒ€์ถœ ์‹œ ํ•„์š” ์ด์ƒ์œผ๋กœ ๋‘๊ป๊ฑฐ๋‚˜ ๋„ˆ๋ฌด ๋งŽ๊ฑฐ๋‚˜ ์ ์€ ์—์ง€๋ฅผ ๊ฒ€์ถœํ•˜๋Š” ๋ถ€๋ถ„์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ์—ฐ์‚ฐ์ž
- ์‚ฌ์šฉ๋ฒ•: cv::Canny(๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ์˜์ƒ, ๊ฒฐ๊ณผ ์™ธ๊ณฝ์„ , ๋‚ฎ์€๊ฒฝ๊ณ„๊ฐ’, ๋†’์€๊ฒฝ๊ณ„๊ฐ’)
- ํžˆ์Šคํ…Œ๋ฆฌ์‹œ์Šค ๊ฒฝ๊ณ„ํ™”๋ผ๊ณ  ํ•˜๋Š”๋ฐ ๋‚ฎ์€ ๊ฒฝ๊ณ„์˜ ๊ฐ’์— ์†ํ•˜๋Š” ์—์ง€๋“ค์„ ๋†’์€ ๊ฒฝ๊ณ„์˜ ๊ฐ’์— ์†ํ•˜๋Š” ์—์ง€์— ์—ฐ๊ฒฐํ•˜๋„๋ก ์ฒ˜๋ฆฌํ•œ๋‹ค. ๊ณ ๋ฆฝ๋œ ์• ๋“ค์€ ์ œ๊ฑฐํ•œ๋‹ค.
- ๊ณ„์‚ฐ ๋ณต์žก๋„์˜ ๋น„์šฉ์ด ํฌ๊ธดํ•˜๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํžˆ์Šคํ…Œ๋ฆฌ์‹œ์Šค ๊ฒฝ๊ณ„ํ™”ํ•˜๊ธฐ์ „์— ๊ธฐ์šธ๊ธฐ ๋ฐฉํ–ฅ์—์„œ ๊ธฐ์šธ๊ธฐ ๊ฐ•๋„๊ฐ€ ์ตœ๋Œ€๊ฐ€ ์•„๋‹Œ ๋ชจ๋“  ์ ์„ ์ œ๊ฑฐํ•œ๋‹ค.
2) ์˜์ƒ์—์„œ ํ•˜ํ”„ ๋ณ€ํ™˜์œผ๋กœ ์„  ๊ฒ€์ถœ
- ์˜์ƒ์—์„œ ์ง์„ ์ด ๋งŽ์€๋ฐ ์ง์„ ์€ ๊ฐ์ฒด ์ธ์‹๊ณผ ์˜์ƒ ์ดํ•ด์˜ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•œ๋‹ค.
- ํ—ˆํ”„ ๋ณ€ํ™˜(Hough transform)์€ ์˜์ƒ์—์„œ ํŠน์ •ํ•œ ํŠน์ง•์„ ๊ฒ€์ถœํ•  ๋•Œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ณ ์ „์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค. ์ดˆ๊ธฐ์— ์˜์ƒ์—์„œ ์„ ์„ ๊ฒ€์ถœํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์กŒ๋‹ค.
- p = xcos@ + ysin@ ๋ฐฉ์ •์‹์„ ์‚ฌ์šฉํ•ด ์„ ์„ ํ‘œํ˜„ํ•œ๋‹ค.
- ์‚ฌ์šฉ๋ฒ•: cv::HoughLines(์„  ํ˜•ํƒœ๋กœ ์ •๋ ฌ๋œ ์  ์ง‘ํ•ฉ, ๊ตฌํ•ด์ง„ ์ด์ง„ ๋งต) ๊ฒฐ๊ณผ๋Š” cv::Vec2f ์š”์†Œ์˜ ๋ฐฑํ„ฐ ์„ (p,@)์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ‘œํ˜„ํ•˜๋Š” ๊ฐ’์ด๋‹ค.
- ์บ๋‹ˆ ์—ฐ์‚ฐ์ž๋ฅผ ์ ์šฉํ•œ ํ›„ ํ—ˆํ”„ ๋ณ€ํ™˜์„ ์‚ฌ์šฉํ•ด ์„ ์„ ๊ฒ€์ถœํ•˜๋Š” ํŽธ์ด๋‹ค.
- ํ—ˆํ”„ ๋ณ€ํ™˜์€ ์˜์ƒ์— ๊ฑธ์นœ ์—์ง€ ํ™”์†Œ์˜ ์ •๋ ฌ์„ ๋‹จ์ˆœํ•˜๊ฒŒ ์ฐพ๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฐœ์ ์ธ ํ™”์†Œ ์ •๋ ฌ์ด๋‚˜ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์„ ์ด ๋™์ผํ•œ ํ™”์†Œ ์ •๋ ฌ์„ ํ†ตํ•ด ์ง€๋‚˜๊ฐˆ ๋•Œ ๋‹ค์ค‘ ๊ฒ€์ถœ์„ ํ•  ์šฐ๋ ค๊ฐ€ ์žˆ๋‹ค.
- ์ด ๋ฌธ์ œ๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด ์„ ๋ถ„ ๊ฒ€์ถœ์„ ํ—ˆ์šฉํ•˜๋Š” ํ—ˆํ”„ ๋ณ€ํ™˜์˜ ๋ณ€์ข…์ด ์ œ์•ˆ๋๋‹ค. ํ™•๋ฅ ์  ํ—ˆํ”„ ๋ณ€ํ™˜์ด๋ฉฐ cv::HoughLinesP ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„๋œ๋‹ค.
- ํ™•๋ฅ ์  ํ—ˆํ”„ ๋ณ€ํ™˜์€ ๋ช‡๊ฐ€์ง€ ์ˆ˜์ •์„ ๋”ํ–ˆ๋‹ค. ๋ฐ›์•„๋“ค์ด๊ธฐ ์œ„ํ•œ ์„ ๋ถ„์˜ ์ตœ์†Œ๊ธธ์ด, ํ—ˆ์šฉํ•˜๋Š” ์ตœ๋Œ€ ํ™”์†Œ ๊ฐ„๊ฒฉ์„ ์ •ํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฌด์ž‘์œ„ ์ˆœ์„œ๋กœ ์ ์„ ์„ ํƒํ•ด ๋ˆ„์‚ฐ๊ธฐ์˜ ํ•ญ๋ชฉ์ด ์ง€์ •๋œ
์ตœ์†Ÿ๊ฐ’์— ๋„๋‹ฌํ•  ๋•Œ๋งˆ๋‹ค ๋Œ€์‘ํ•˜๋Š” ์„ ์„ ๋”ฐ๋ผ ์˜์ƒ์„ ์กฐํšŒํ•œ ํ›„ ํ•ด๋‹น ์„ ์„ ํ†ต๊ณผํ•ด ์ง€๋‚˜๊ฐ€๋Š” ๋ชจ๋“  ์ ์„ ์ œ๊ฑฐํ•œ๋‹ค.(์„ ์— ํˆฌํ‘œ๋ฅผ ์•„์ง ์•ˆํ•ด๋„)
- ํ—ˆํ”„ ๋ณ€ํ™˜์€ ์ถฉ๋ถ„ํ•œ ์  ๊ฐœ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ ๊ทธ ์ ๋“ค์„ ์ง€๋‚˜๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์„ ๋ถ„์„ ๊ตฌํ•ด์„œ ๋™์ผํ•œ ์„ ๋ถ„์ด ๋งŽ์€ ์ ์„ ํ†ตํ•ด ์ง€๋‚˜๊ฐˆ ๋•Œ ์ด ์„ ์„ ์ฐพ๋Š” ์‹์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค.
- ํ—ˆํ”„ ๋ณ€ํ™˜์€ ์ฃผ์–ด์ง„ ์„ ์„ ์–ผ๋งˆ๋‚˜ ์‹๋ณ„ํ–ˆ๋Š”์ง€ ์„ธ๊ธฐ ์œ„ํ•ด 2์ฐจ์› ๋ˆ„์‚ฐ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์„œ๋กœ ๋‹ค๋ฅธ (p, @) ๊ฐ’์˜ ๋งคํ•‘์ด๋‹ค. ๊ฐ’๋“ค์€ ์„ ์ด๋‹ค.
3) ์› ๊ฒ€์ถœ
- ์›์ธ ๊ฒฝ์šฐ ๋ฐฉ์ •์‹์€ r^2 = (x - x0)^2 + (y - y0)^2 3์ฐจ์› ๋ˆ„์‚ฐ๊ธฐ๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ ์ •๋ฐ€ํ•˜๊ฒŒ ํ•˜๊ธฐ์œ„ํ•ด 2์ฐจ์› ๋ˆ„์ ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•  ์ˆ˜ ์žˆ๋‹ค.
- ์šฐ์„  ๊ฐ€๋Šฅํ•œ ์›์˜ ์ค‘์‹ฌ์„ ๊ฒ€์ถœํ•˜๊ณ , ๊ฐ€๋Šฅํ•œ ๋ฐ˜์ง€๋ฆ„์˜ 1D ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๋‘ ๋ฒˆ์งธ ํŒจ์Šค๋ฅผ ํ•˜๋Š” ๋™์•ˆ์— ๊ตฌ์ถ•ํ•œ๋‹ค.
- HoughCircles()ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ž˜๋ชป๋œ ์› ๊ฒ€์ถœ์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” ์˜์ƒ ์žก์Œ์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ์˜์ƒ์„ blur๋กœ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ํ•ด์•ผํ•œ๋‹ค.
4) ์„ ์„ ์  ์ง‘ํ•ฉ์— ๋งž์ถ”๊ธฐ
- ์ •ํ™•ํ•˜๊ฒŒ ์ถ”์ •ํ•œ ์„ ์˜ ์œ„์น˜์™€ ๋ฐฉํ–ฅ์„ ์–ป๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•  ์ˆ˜ ์žˆ๋‹ค.
- cv::HoughLinesP๋ฅผ ์‚ฌ์šฉํ•ด ๊ฒ€์ถœํ•œ ์„ ์€ vector<cv::Vec4i>์— ํฌํ•จ๋˜๋Š”๋ฐ ์ด๊ฒƒ๊ณผ ์™ธ๊ณฝ์„ ์˜ ์บ๋‹ˆ ์˜์ƒ์„ ๊ฐ–๊ณ  ๊ต์ฐจํ•˜๋Š” ์„ ์„ ๊ตฌํ•ด ์ฒซ ๋ฒˆ์งธ์— ์†ํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ด๋Š” ์  ์ง‘ํ•ฉ์„ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.
- ์ถ”์ถœํ•œ ์ ๋“ค์˜ ์ง‘ํ•ฉ์„ vector์— ์ง‘์–ด๋„ฃ๊ณ  cv::fitLine ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ตœ์ ์œผ๋กœ ๋งž์ถ˜ ์„ ์„ ์‰ฝ๊ฒŒ ์ฐพ๋Š”๋‹ค. vector<Vec4f>์˜ ์ฒซ ๋‘ ๊ฐ’์€ ๋‹จ์ผ ๋ฐฉํ–ฅ ๋ฒกํ„ฐ๊ณ , ๋งˆ์ง€๋ง‰ ๋‘ ๊ฐ’์€ ํ•œ ์ ์˜ ์ขŒํ‘œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
- ์ด๊ฑธ ์ด์šฉํ•ด ์„ ์„ ๊ทธ๋ฆฌ๋ฉด ๋œ๋‹ค.
- cv::fitEclipse ํ•จ์ˆ˜๋Š” ํƒ€์›์„ 2D ์  ์ง‘ํ•ฉ์— ๋งž์ถ”๋ฉฐ, ํšŒ์ „๋œ ์‚ฌ๊ฐํ˜•(cv::RotatedRect ์ธ์Šคํ„ด์Šค)๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด๋•Œ ์ด ์‚ฌ๊ฐํ˜• ์•ˆ์— ํƒ€์›์ด ์ƒˆ๊ฒจ์ ธ ์žˆ๋‹ค.
5) ์—ฐ๊ฒฐ ์„ฑ๋ถ„ ์ถ”์ถœ
- ๊ฐ์ฒด ํ‘œํ˜„์„ ์œ„ํ•ด์„œ ์ฒซ ๋ฒˆ์งธ๋กœ ํŠน์ • ๊ด€์‹ฌ ๊ฐœ์ฒด๊ฐ€ ์œ„์น˜ํ•œ๋‹ค๋Š” ๊ฑธ ๋ณด์—ฌ์ฃผ๋Š” ์ด์ง„ ์˜์ƒ์„ ์ƒ์„ฑํ•˜๊ณ , ๋‘ ๋ฒˆ์งธ๋กœ 0, 1๋กœ ๊ตฌ์„ฑ๋œ ์ง‘๋‹จ์„ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ถ”์ถœํ•œ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ์ด๋Ÿฐ ์˜์ƒ์˜ ์—ฐ๊ฒฐ ์„ฑ๋ถ„(์—ฐ๊ฒฐ๋œ ํ™”์†Œ ์ง‘ํ•ฉ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ๋ชจ์–‘)์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ถ”์ถœํ•œ๋‹ค
- cv::findContours() ์—ฐ๊ฒฐ์„ฑ๋ถ„์˜ ์™ธ๊ณฝ์„ ์„ ๊ตฌํ•˜๋Š” ํ•จ์ˆ˜, cv::drawContours() ์™ธ๊ณฝ์„  ๋ฐฑํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ๊ทธ๋ฆฌ๋Š” ํ•จ์ˆ˜.
- ๊ฐœ๋ณ„๋กœ ๋ถ„์„ํ•ด์„œ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๊ณ  ์™ธ๊ณฝ์„ ์„ ๊ณ„์ธต์œผ๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.
6) ์„ฑ๋ถ„ ๋ชจ์–‘์˜ ๊ธฐ์ˆ ์ž ๊ณ„์‚ฐ
- ์—ฐ๊ฒฐ ์„ฑ๋ถ„์˜ ๋ชจ์–‘์„ ๊ธฐ์ˆ ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ๋ชจ์–‘ ๊ธฐ์ˆ ์ž๋ผ๊ณ  ํ•œ๋‹ค.
- ๊ฒฝ๊ณ„ ์ƒ์ž cv::boundingRect(); -> cv::rectangle();
==> ์ •ํ™•ํ•˜๊ฒŒ ์ฐพ์•„๋‚ด๊ธฐ ๊ฐ€์žฅ ๊ฐ„๊ฒฐํ•œ ๋ฐฉ๋ฒ•, ๋ณดํ–‰์ž ์˜์ƒ๊ณผ ์ž๋™์ฐจ ์˜์ƒ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด ์ข…ํšก๋น„ ์‚ฌ์šฉ.
- ๊ฐ€์žฅ ์ž‘์€ ๋‘˜๋Ÿฌ์‹ผ ์› cv::minEnclosingCircle(); -> cv::circle();
==> ๊ทผ์‚ฌํ™”ํ•œ ์„ฑ๋ถ„ ํฌ๊ธฐ์™€ ์œ„์น˜๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ
- ๋‹ค๊ฐํ˜• ๊ทผ์‚ฌ cv::approxPolyDP(); -> cv::polylines();
==> ๋ชจ์–‘๊ณผ ๋น„์Šทํ•œ ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•œ ํ‘œํ˜„์„ ๋‹ค๋ฃจ๊ณ  ์‹ถ์„ ๋•Œ ์œ ์šฉ
- ๋ธ”๋ก ๊ป์งˆ cv::convexHull(); -> cv::polylines();
==> ๋ชจ์–‘์„ ์—์›Œ์‹ผ ์ตœ์†Œ ๋ธ”๋ก ๋‹ค๊ฐํ˜•, ์˜ค๋ชฉํ•œ ์œ„์น˜์—์„œ ๋ฒ—์–ด๋‚˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
- ๋ชจ๋ฉ˜ํŠธ ๊ณ„์‚ฐ(๋ชจ๋“  ์„ฑ๋ถ„ ๋‚ด๋ถ€์— ์งˆ๋Ÿ‰ ์ค‘์‹ฌ[๋ฌด๊ฒŒ ์ค‘์‹ฌ]์„ ๊ทธ๋ฆฐ๋‹ค.)
cv::Moments mom = cv::moments(cv::Mat(*itc++));
cv::circle(result, cv::Point(mom.m10/mom.m00, mom.m01/mom.m00),2,cv::Scalar(0),2);
๊ทธ ์™ธ์—๋„
cv::convexityDefects() ๋ธ”๋ก ๊ฒฐ์†์œผ๋กœ ์ง€์ •๋˜๋Š” ์œ„์น˜๋ฅผ ์‹๋ณ„ํ•˜๋Š” ํŠน๋ณ„ํ•œ ํ•จ์ˆ˜
cv::minAreaRect() ๊ฐ€์žฅ ์ž‘์€ ํšŒ์ „๋œ ์‚ฌ๊ฐํ˜•์„ ๊ณ„์‚ฐํ•œ๋‹ค.
cv::contourArea() ์™ธ๊ณฝ์„ (์•ˆ์— ์žˆ๋Š” ํ™”์†Œ ๊ฐœ์ˆ˜)์˜ ๋ฉด์ ์„ ์ถ”์ •ํ•œ๋‹ค.
cv::pointPolygenText() ์ ์ด ์™ธ๊ณฝ์„  ๋‚ด๋ถ€์— ์žˆ๋Š”์ง€ ์™ธ๋ถ€์— ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.
cv::matchShapes() ๋‘ ์™ธ๊ณฝ์„ ์˜ ์œ ์‚ฌ์„ฑ์„ ์ธก์ •ํ•œ๋‹ค.
7) ์‚ฌ๋ณ€ํ˜• ๊ฒ€์ถœ
- MSER ํŠน์ง•์€ ์˜์ƒ์—์„œ ๋ชจ์–‘์„ ์ถ”์ถœํ•˜๊ธฐ ์œ„ํ•œ ํšจ์œจ์ ์ธ ๋„๊ตฌ๊ฐ€ ๋œ๋‹ค. ์‚ฌ๋ณ€ํ˜•(quadrilateral)
- ํ˜•ํƒœํ•™ ํ•„ํ„ฐ๋กœ ์ •๋ฆฌ ํ›„ -> ์™ธ๊ณฝ์„  ์–ป๊ณ  -> ์™ธ๊ณฝ์„ ์„ ์ˆœํšŒํ•˜๋ฉด์„œ ์™ธ๊ณฝ์„ ์„ ๋‹ค๊ฐํ˜•์œผ๋กœ ๊ฑฐ์˜ ๊ทผ์‚ฌํ™” ํ•œ๋‹ค.
- ์‚ฌ๊ฐํ˜•์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ฒ€์ถœํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์ธ์ ‘ํ•œ ์—์ง€ ๊ฐ„์˜ ๊ฐ๋„๋ฅผ ์ธก์ •ํ•œ ํ›„ 90๋„์—์„œ ๋„ˆ๋ฌด๋‚˜ ๋งŽ์ด ๋ฒ—์–ด๋‚œ ๊ฐ๋„๋ฅผ ๊ฐ–๋Š” ์‚ฌ๋ณ€ํ˜•์„ ๋ฐฐ์ œํ•˜๋ฉด ๋œ๋‹ค.
============= openCV ํด๋ž˜์Šค์™€ ํ•จ์ˆ˜ ์ •๋ฆฌ =============
๊ฐ€. cv::Mat - ๊ธฐ๋ณธ์ ์ธ ์˜์ƒ์„ ๋‹ด์„ ํด๋ž˜์Šค, ํ–‰๋ ฌ์ด๋‹ค.
ex) cv::Mat image; ํฌ๊ธฐ๊ฐ€ 0x0์ธ ๋นˆ ์˜์ƒ(image) ์ƒ์„ฑ.
- ํ—ค๋”์™€ ๋ฐ์ดํ„ฐ ๋ธ”๋ก(=๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก)์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์œผ๋ฉฐ, ํ—ค๋”์—๋Š” ํ–‰๋ ฌ๊ณผ ๊ด€๋ จ์žˆ๋Š” ๋ชจ๋“ ์ •๋ณด(ํฌ๊ธฐ, ์ฑ„๋„ ์ˆ˜, ์ž๋ฃŒํ˜• ๋“ฑ)๊ฐ€ ๋“ค์–ด ์žˆ๊ณ , ๋ฐ์ดํ„ฐ ๋ธ”๋ก์—๋Š” ์˜์ƒ์˜ ๋ชจ๋“  ํ™”์†Œ ๊ฐ’์ด ๋“ค์–ด์žˆ๋‹ค.
- ํ—ค๋”์—๋Š” ๋ฐ์ดํ„ฐ ๋ธ”๋ก(= data์†์„ฑ)์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ ๋ณ€์ˆ˜๊ฐ€ ๋“ค์–ด์žˆ๋‹ค. ๊ฐ™์€ ๋ฐ์ดํ„ฐ ๋ธ”๋ก์„ ๊ฐ€๋ฆฌํ‚ค๊ธฐ ์œ„ํ•ด ํ—ค๋”๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ๊ฒƒ์€ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
- ์ƒ์„ฑ์ž๋กœ (int rows, int cols, int type, int scalar); ์ƒ์„ฑ๊ฐ€๋Šฅ //์„ธ๋กœ๊ธธ์ด, ๊ฐ€๋กœ๊ธธ์ด, ํƒ€์ž…, ์ƒ‰
ex) cv::Mat abc(240,320,CV_8U,cv::Scalar(100)); // 240ํ–‰ 320์—ด ์˜์ƒ ์ƒ์„ฑ CV_8U ์—์„œ U๋ฌธ์ž๋Š” ๋ถ€ํ˜ธ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๊ณ  S๋Š” ๋ถ€ํ˜ธ ์žˆ๋Š” ์ˆซ์ž ๊ฐ€๋Šฅ. F๋ถ€๋™์†Œ์ˆซ์  ์ˆซ์ž. C์ฑ„๋„.
- Range๋ฅผ ์‚ฌ์šฉํ•œ ์ƒ์„ฑ์ž (cv::Range rowsRange, cv::Range colsRange) //์„ธ๋กœ, ๊ฐ€๋กœ
- Rect๋ฅผ ์‚ฌ์šฉํ•œ ์ƒ์„ฑ์ž (cv::Rect ROIRect) //ROI๋ฅผ ์œ„ํ•œ ์ƒ์„ฑ์ž
- ๋ณ€์ˆ˜์— ๊ฐ’์„ ํ• ๋‹นํ•˜๋Š” ๊ฒฝ์šฐ, scalar๊ฐ’(์ƒ‰)์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.
ex) iamge1 = 200; // ๋งŒ์•ฝ CV_8U๋ผ๋ฉด 0-255;200์ด๋ฏ€๋กœ ๋ฐ์€ ํšŒ์ƒ‰์ด ๋  ๊ฒƒ์ด๋‹ค.
1) int rows, int cols - ์„ธ๋กœ๊ธธ์ด, ๊ฐ€๋กœ๊ธธ์ด ์†์„ฑ.
2) cv::MatSize size - ์‚ฌ์ด์ฆˆ ์•Œ๋ ค์ฃผ๋Š” ์†์„ฑ.
3) bool empty() - ๋น„์–ด์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ•จ์ˆ˜ (์œ ํšจํ•œ์ง€ ํ™•์ธํ•  ๋•Œ ์”€).
ex) if(image.empty()) return 0; == if(!image.data) return 0;
4) int channels() - ์˜์ƒ์˜ ์ฑ„๋„๊ฐœ์ˆ˜ ํ™•์ธํ•˜๋Š” ํ•จ์ˆ˜
5) <type> at<type>(Pointype) - ํ™”์†Œ(ํ–‰๋ ฌ์˜ ์›์†Œ)์— ์ ‘๊ทผํ•˜๋Š” ํ•จ์ˆ˜, ํ™”์†Œ๊ฐ’์„ ์–ป๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜.
- atํ•จ์ˆ˜๋Š” ์–ด๋– ํ•œ ํƒ€์ž…๋ณ€ํ™˜๋„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค.
ex) image.at<uchar>(j,i) = 255;
ex) image.at<cv::Vec3b>(j,i) = cv::Vec3b(255, 255, 255);
- atํ•จ์ˆ˜๋Š” ๋ฌด์ž‘์œ„๋กœ ํ™”์†Œ์— ์ ‘๊ทผํ•ด์•ผํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•˜๋Š”ํŽธ์ด ์ข‹๊ณ , ์˜์ƒ ์ „์ฒด๋ฅผ ์กฐํšŒํ•  ๋•Œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ๋ง์•„์•ผํ•œ๋‹ค.
6) void create(int rols, int cols, int type) - ์˜์ƒ์„ ํ• ๋‹นํ•˜๊ฑฐ๋‚˜ ์žฌํ• ๋‹นํ•˜๋Š” ํ•จ์ˆ˜, ์žฌํ• ๋‹น ์‹œ ํฌ๊ธฐ ๋ฐ ํƒ€์ž…์ด ์ผ์น˜ํ•˜๋ฉด ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค.
7) cv::Mat clone(), void copyTo(cv::Mat targetMat) - ์˜์ƒ์„ ๊นŠ์€๋ณต์‚ฌ ์‹œํ‚ฌ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ณ€์ˆ˜. ๊ฐ’ ๋ณ€๊ฒฝ์ด ์˜ํ–ฅ์„ ๋ผ์น˜์ง€ ์•Š๊ฒŒ ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ๋ชฉ์ ์˜์ƒ์— create()ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ ํ•œ๋‹ค.
ex) image1.create(200,200,CV_8U);
8) void convertTo(cv::Mat targetMat, int type, double alpha=(1.0), double delta=(0.0)) - ์˜์ƒ์„ ๋‹ค๋ฅธ ์ž๋ฃŒํ˜•์˜ ํ˜•ํƒœ๋กœ ๋ณต์‚ฌํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ๋‹จ, ๋ฐ˜๋“œ์‹œ ๋‘ ๋Œ€์ƒ์˜ ์ฑ„๋„์ด ๊ฐ™์•„์•ผํ•œ๋‹ค.
ex) image1.convertTo(image2,CV_32F,1/255.0,0.0); //์ธ์ž์˜ alpha์ž๋ฆฌ๋Š” scaling factor(์ถ•์  ๊ณ„์ˆ˜), delta์ž๋ฆฌ๋Š” offset(์˜คํ”„์…‹)์ด๋‹ค.
// ์—ฌ๊ธฐ์„œ [0-1]์ธ ๋ถ€๋™์†Œ์ˆ˜์ ํ˜•์œผ๋กœ ๋ฐ”๊พธ๋Š”๊ฒƒ ์ด๊ธฐ์— [0-255] / 255 = 1/255.0์„ ์ถ•์  ๊ณ„์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
9) cv::Mat rowRange(int start, int end), cv::Mat colRange(int start, int end) - ROI์šฉ ํ–‰/์—ด ์ผ๋ถ€๋ฅผ ์ง€์ •ํ•˜๋Š” ์ฝ”๋“œ.
ex) cv::Mat imageROI = image.rowRange(start, end);
- cv::Mat๋Š” ์ฐธ์กฐ ์นด์šดํŒ…๊ณผ ์–•์€ ๋ณต์‚ฌ๋ฅผ ๊ตฌํ˜„ํ•ด ๋†“์•˜๊ธฐ์— ํŽธ์ง‘ ์‹œ ๋‹ค๋ฅธ์˜์ƒ์—๋„ ์˜ํ–ฅ์„ ์ฃผ๋Š” ์ฐธ์กฐํ˜•(์–•์€๋ณต์‚ฌ)ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™๊ณ , (ํ•จ์ˆ˜๋‚˜ ํด๋ž˜์Šค์—์„œ๋„ ๊ทธ๋ƒฅ Mat๋ฅผ ๋ฆฌํ„ด ์‹œ์—๋Š” ์•์€๋ณต์‚ฌ๋‹ค!)
ex) cv::Mat image4(image3) ;
image1 = image3;
๊นŠ์€ ๋ณต์‚ฌ๋Š” copyTo()์ด๋‚˜ clone() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
ex) image3.copyTo(image2);
cv::Mat image5 = image3.clone();
10) cv::Mat_<type> ํด๋ž˜์Šค - cv::Mat์˜ ํ…œํ”Œ๋ฆฟ ์„œ๋ธŒํด๋ž˜์Šค๋กœ์„œ, ๋ช‡ ๊ฐ€์ง€ ๋ณด์กฐ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ ์žˆ๋‹ค.
- operator() ๋ณด์กฐ ๋ฉ”์„œ๋“œ๋กœ ํ–‰๋ ฌ ์›์†Œ(Pixel)์— ์ง์ ‘ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. (at() ๋Œ€์šฉ)
ex) cv::Mat_<uchar> im2(image);
im2(50,100) = 0;
ex) cv::Mat_<uchar>& im2= reinterpret_cast<cv::Mat_<uchar>&>(image); //์ฐธ์กฐํ˜•์œผ๋กœ ์„ ์–ธํ•˜๋Š” ๋ฒ•
im2(50,100) = 255;
- cv::Mat_<type>::iterator ๋ฐ˜๋ณต์ž๋ณ€์ˆ˜๋ช… - ์ด๋Ÿฐ์‹์œผ๋กœ ์ •์˜๋œ iterator ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
ex) cv::Mat_<cv::Vec3b>::iterator it;
11) int elemSize() - ํ™”์†Œ์˜ ํฌ๊ธฐ๋ฅผ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
ex) image.elemSize(); // CV_16SC3 ์ด๋ฉด 2*3 = 6
12) int step - ์œ ํšจ ๋„ˆ๋น„(effective width)๋ฅผ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ์ œ๊ณตํ•˜๋Š” ์†์„ฑ. ํ•œ ํ–‰์˜ ๋ฐ”์ดํŠธ ๊ฐœ์ˆ˜((cols [+ extra pixel]) * elemSize)
* ์—ฌ๊ธฐ์„œ ์œ ํšจ๋„ˆ๋น„๋ผ๊ณ  ํ‘œํ˜„ํ•˜๋Š” ์ด์œ ๋Š” ๋ฐ์ดํ„ฐ๊ธธ์ด๋ฅผ ๋งž์ถ”๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€ํ™”์†Œ๊ฐ€ ์ถ”๊ฐ€๋ฌ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
13) int total() - ํ–‰๋ ฌ ๋‚ด์˜ ํ™”์†Œ์˜ ์ด ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
14) <type>* ptr<type>(int rowsNum) - ์˜์ƒ์˜ ํ–‰ ์ฃผ์†Œ๋ฅผ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜. ํ–‰ ๋ฒˆํ˜ธ(rowsNum)์˜ ์ฃผ์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ…œํ”Œ๋ฆฟ ํ•จ์ˆ˜๋‹ค.
ex) uchar* data = image.ptr<uchar>(0); //0๋ฒˆ ํ–‰์˜ ์ฃผ์†Œ๋ฅผ ๋ฐ˜ํ™˜
for (int i = 0; i < nc; i++)
{
data[i] = data[i] / div * div + div / 2; // i๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•
// *data++ = *data / div * div + div / 2; // ํฌ์ธํ„ฐ ์‚ฐ์ˆ ์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
}
- ์˜์ƒ ์กฐํšŒ ์‹œ atํ•จ์ˆ˜๋ณด๋‹ค ๋” ํšจ์œจ์ ์ด๋‹ค.
15) uchar* data - ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก(=๋ฐ์ดํ„ฐ ๋ธ”๋ก)์•ˆ์˜ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ์˜ ์ฃผ์†Œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์†์„ฑ.
16) bool isContinuous() - ์ง๋ ฌ(์ถ”๊ฐ€ ํ™”์†Œ๋ฅผ ์ฑ„์šฐ์ง€ ์•Š์•˜๋Š”์ง€= ์—ฐ์†์„ฑ)์ธ์ง€ ํ™•์ธํ•˜๋Š” ํ•จ์ˆ˜. ์กฐ๊ฑด ( step == cols*elemSize() ) ์™€ ๋™์ผ.
์ถ”๊ฐ€ ํ™”์†Œ๋ฅผ ์ฑ„์šฐ์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ W*H ํ™”์†Œ์˜ ๊ธด 1์ฐจ์› ๋ฐฐ์—ด๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
17) cv::Mat reshape(int newChannelsNum, int newRowsNum) - ๋งคํŠธ์˜ ์ฑ„๋„๊ฐœ์ˆ˜ ํ–‰,์—ด์„ ์žฌ์กฐ์ •ํ•˜๋Š” ํ•จ์ˆ˜ (์ธ์ž 2๊ฐœ ์ž…๋ ฅ์‹œ = ํ–‰์˜ ๊ฐœ์ˆ˜์— ๋”ฐ๋ผ ์—ด ๊ฐœ์ˆ˜๋Š” ์ž๋™์œผ๋กœ ์กฐ์ • ๋จ.)
(์ฐธ๊ณ ๋กœ ์ฑ„๋„๊ฐœ์ˆ˜์— 1์ž…๋ ฅ์‹œ NX1 3์ฑ„๋„ ์ผ ๊ฒฝ์šฐ NX3 1์ฑ„๋„๋กœ ๋ฐ”๋€๋‹ค. ์ฆ‰, 3์ฑ„๋„ ์ค‘ 2๊ฐœ๊ฐ€ ์‚ฌ๋ผ์ง€๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ง๋ ฌํ™” ๋œ๋‹ค๋Š” ๋ง)
์†๋„์ ์ธ ๋ฉด์„๋ดค์„ ๋•Œ ์ง๋ ฌํ™”์‹œ ๋น ๋ฅธ๋ฐฉ๋ฒ•์ด๋‹ค.
18) cv::MatIterator_<type> ํด๋ž˜์Šค - (_ ๊ฐ€ ๋ถ™์œผ๋ฉด ํ…œ.์„œ.) ํ…œํ”Œ๋ฆฟ ์„œ๋ธŒํด๋ž˜์Šค, ๋ฐ˜ํ™˜ํƒ€์ž…์„ type์— ์ ๋Š”๋‹ค. ์˜์ƒ์— ๋Œ€ํ•œ ๋ฐ˜๋ณต์ž ์—ญํ• ์„ ํ•œ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ begin, end๋ฐ˜๋ณต์ž ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด ํ™”์†Œ๋ฅผ ์ˆœํšŒํ•œ๋‹ค.
- begin ๋ฉ”์†Œ๋“œ๋Š” ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ฐ˜๋ณต์ž๋ฅผ ๋ฐ˜ํ™˜, ๊ทธ๋Ÿฌ๋‚˜ end ๋ฉ”์†Œ๋“œ๋Š” ๋งˆ์ง€๋ง‰ ์š”์†Œ์˜ ๋‹ค์Œ, ์ฆ‰ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ณณ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ฐ˜๋ณต์ž๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
ex) cv::MatIterator_<cv::Vec3b> it = image.begin<cv::Vec3b>();
cv::MatIterator_<cv::Vec3b> itend = image.end<cv::Vec3b>();
uchar div2 = div >> 1;
for (; it != itend; it++)
{
(*it)[0] = (*it)[0] / div * div + div2;
(*it)[1] = (*it)[1] / div * div + div2;
(*it)[2] = (*it)[2] / div * div + div2;
}
- ๋ฐ˜๋ณต์ž๋กœ ์‚ฐ์ˆ ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ์˜์ƒ์˜ ๋‘ ๋ฒˆ์งธ ํ–‰์—์„œ ์‹œ์ž‘ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด image.begin() + image.cols, ๋งˆ์ง€๋ง‰ ํ–‰ ์ „์— ์ค‘๋‹จํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด image.end() - image.cols ์ด๋Ÿฐ์‹์œผ๋กœ ๊ฐ€๋Šฅ.
- ๋ฐ˜๋ณต์ž๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์—ญ์ฐธ์กฐ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค. element = *it; ์ฝ๊ธฐ, *it = element; ์“ฐ๊ธฐ
- ์ƒ์ˆ˜๋ฐ˜๋ณต์ž๋„ ์žˆ๋‹ค. cv::MatConstInterator_<type> ๋ฐ˜๋ณต์ž๋ช… or cv::Mat_<type>::const_iterator ๋ฐ˜๋ณต์ž๋ช… ์ด๋ ‡๊ฒŒ ์„ ์–ธ๊ฐ€๋Šฅ.
- iterator๊ฐ€ ์–‘์ด ๋งŽ์ง€ ์•Š๋‹ค๋ฉด ๋น ๋ฅด์ง€ ์•Š๋‹ค. ๋งŽ์„ ๋•Œ ์œ ๋ฆฌ.
19) cv::MatIterator_<type> begin(), end() - ์ฒซ ๋ฒˆ์งธ ์š”์†Œ, ๋งˆ์ง€๋ง‰ ์š”์†Œ์˜ ๋‹ค์Œ ์œ ํšจํ•˜์ง€ ์•Š๋Š” ๊ณณ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ฐ˜๋ณต์ž๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
- Mat_๋กœ ์ƒ์„ฑ๋œ ๊ฐ์ฒด์—์„œ๋„ begin(), end()๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด๋•Œ๋Š” ์ƒ์„ฑ์‹œ ํƒ€์ž…์„ ์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— <type>์„ ์“ฐ์ง€์•Š์•„๋„ ๋œ๋‹ค.
ex) cv::Mat_<cv::Vec3b> cimage(image);
cv::Mat_<cv::Vec3b>::iterator it = cimage.begin();
20) cv::Mat setTo(cv::InputArray value,cv::InputArray mask = noArray()) - ํŠน์ • ์š”์†Œ๊ฐ’์„ ํŠน์ •์ˆ˜์น˜๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ. ๋Œ€๋Ÿ‰์œผ๋กœ ๋ฐ”๊ฟ€ ๋•Œ ์‚ฌ์šฉ.
ex) result.row(0).setTo(cv::Scalar(0)); ์ฒซ ๋ฒˆ์งธ ํ–‰์„ ๊ฒ€์€์ƒ‰์œผ๋กœ ๋ฐ”๊พผ๋‹ค.
21) int dims - ์ฐจ์›์˜ ๊ฐœ์ˆ˜๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ์†์„ฑ
ex) for (int i = 0; i < histogram.dims; i++) //histogram์ด 3์ฐจ์›์ด๋ฉด 3
๋‚˜. Mat cv::imread(String filename, [int option]) - ์˜์ƒ์„ ์ฝ์–ด ๋””์ฝ”๋”ฉํ•˜๊ณ  ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹นํ•˜๋Š” ์ฝ๊ธฐ ํ•จ์ˆ˜
ex) image = cv::imread("puppy.jpg");
- ์ง€์›ํ•˜๋Š” ํฌ๋งท์€ bmp, jpg, tiff, png ๋“ฑ๋“ฑ.
- ์ƒ๋Œ€์œ„์น˜์˜ ํ˜„์žฌ์œ„์น˜๋Š” .cpp ํŒŒ์ผ์˜ ์œ„์น˜์ด๋ฉฐ ํ™•์žฅ์ž๋„ ํฌํ•จํ•ด์•ผํ•œ๋‹ค.
- ์ ˆ๋Œ€์œ„์น˜๋Š” "D:\image\test.jpg" ์ด๋Ÿฐ์‹์œผ๋กœ ํ‘œํ˜„
- ์˜์ƒ์„ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ์˜์ƒ์œผ๋กœ ์ฝ์–ด์˜ค๋Š” ์˜ต์…˜์ด ์žˆ๋Š”๋ฐ, ์ด๊ฒƒ์ด ํฐ ์žฅ์ ์ด ๋˜๋Š” ์ด์œ ๋Š”
์—ฌ๋Ÿฌ ์ปดํ“จํ„ฐ ๋น„์ „ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ์˜์ƒ์„ ์š”๊ตฌํ•˜๊ณ , ์ž…๋ ฅ ์ปฌ๋Ÿฌ ์˜์ƒ์„ ์ฆ‰์‹œ ๋ณ€ํ™˜ํ•˜๊ธฐ์— ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•˜๊ณ  ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ตœ์†Œํ™” ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
- [์˜ต์…˜] 1) CV_LOAD_IMAGE_GRAYSCALE or 0 - ๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ ์˜์ƒ, CV_8U ๋ถ€ํ˜ธ ์—†๋Š” ๋ฐ”์ดํŠธ(C++์˜ unsigned char)
2) CV_LOAD_IMAGE_COLOR or 1 - 3์ฑ„๋„ ์˜์ƒ(์ƒ๋žต ์‹œ ๋””ํดํŠธ), CV_8UC3 ํ™”์†Œ ๋‹น 3๋ฐ”์ดํŠธ
3) ์Œ์ˆ˜ ๊ฐ’ ์ž…๋ ฅ ์‹œ - ์˜์ƒ์„ ์ €์žฅํ–ˆ๋˜ ํฌ๋งท ๊ทธ๋Œ€๋กœ (alpha ์ฑ„๋„= ํˆฌ๋ช…ํ•œ ๊ฒƒ์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ์‹ถ์œผ๋ฉด ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฐ–์— ์—†๋‹ค.)
4) CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR - ์˜์ƒ์˜ ๊นŠ์ด์™€ ์ปฌ๋Ÿฌ/๊ทธ๋ ˆ์ด๋ ˆ๋ฒจ๊ณผ ์ƒ๊ด€์—†์ด ์•ˆ์ „ํ•˜๊ฒŒ ์ฝ์–ด์˜ฌ ์ˆ˜
์žˆ์–ด์„œ ์ด๋Ÿฐ์‹์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•œ๋‹ค.
๊ทธ ์™ธ ๋” ์ž์„ธํ•œ ์˜ต์…˜๊ณผ ๋‚ด์šฉ.
IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped).
IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image.
IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image.
IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format.
IMREAD_LOAD_GDAL = 8, //!< If set, use the gdal driver for loading the image.
IMREAD_REDUCED_GRAYSCALE_2 = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2.
IMREAD_REDUCED_COLOR_2 = 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.
IMREAD_REDUCED_GRAYSCALE_4 = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4.
IMREAD_REDUCED_COLOR_4 = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
IMREAD_REDUCED_GRAYSCALE_8 = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
IMREAD_REDUCED_COLOR_8 = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag.
๋‹ค. void cv::namedWindow(String windowname) - ์ฐฝ ์ •์˜ํ•˜๋Š” ํ•จ์ˆ˜ (๋””ํดํŠธ ์ฐฝ์˜ ์ด๋ฆ„์„ ๋ฐ”๊พธ๊ฑฐ๋‚˜, ์ฐฝ ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜๋ผ๊ณ  ๋ด๋„ ๋จ.)
ex) cv::namedWindow("Original Image");
- ์ฐฝ์„ ์ด๋ฆ„์œผ๋กœ ์‹๋ณ„ํ•œ๋‹ค. ์ฆ‰, ์ฐฝ์„ ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
๋ผ. void cv::imshow(String windowname, Mat showmat) - ์˜์ƒ์„ ํŠน์ • ์ฐฝ์— ๋ณด์—ฌ์ค„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜ (๋งŒ์•ฝ, ์—†๋Š” ์ด๋ฆ„์˜ ์ฐฝ์„ ์ ์œผ๋ฉด, ์ž๋™์œผ๋กœ ๊ทธ ์ด๋ฆ„์œผ๋กœ ์ฐฝ์ด ์ƒ์„ฑ๋˜๊ณ  ๊ฑฐ๊ธฐ์— ๋ณด์—ฌ์ง„๋‹ค.)
ex) cv::imshow("Original Image", image);
๋งˆ. int cv::waitKey(int key) - ํŠน์ • ์‹œ๊ฐ„๋™์•ˆ ์‚ฌ์šฉ์ž ํ‚ค ์ž…๋ ฅ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ํ•จ์ˆ˜ (์ธ์ž๊ฐ€ 0์ผ ๋•Œ๋‚˜ ์—†์„ ๋•Œ๋Š” ๋ฌด์ œํ•œ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. ์–‘์ˆ˜ ์ผ๋•Œ๋Š” ms๋™์•ˆ ๊ธฐ๋‹ค๋ฆผ)
ex) cv::waitKey(0); = cv::waitKey();
- ์ด๊ฑธ ํ™œ์šฉํ•ด์„œ ์ฝ˜์†”์—์„œ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ผ์‹œ์ •์ง€์‹œํ‚ค๋ฉด ํ…Œ์ŠคํŒ…ํ•˜๊ธฐ ์ข‹๋‹ค. ๊ทธ๋Ÿฐ์šฉ๋„๋กœ ์จ๋ณด์ž.
๋ฐ”. void cv::filp(Mat Ori, Mat Changed, int method) - ์˜์ƒ์„ ๋’ค์ง‘๊ธฐ ํ•˜๋Š” ํ•จ์ˆ˜ (์ˆ˜ํ‰์ด๋ฉด ์–‘์ˆ˜, ์ˆ˜์ง์ด๋ฉด 0, ๋‘˜๋‹ค๋ฉด ์Œ์ˆ˜)
ex) cv::filp(image, image, 1); cv::Mat result; cv::filp(image, result, -1);
- ์ž๊ธฐ ์ž์‹ ๋ณ€์ˆ˜์— ๋„ฃ๊ฑฐ๋‚˜(in-place ๋ฐฉ๋ฒ•), ๋‹ค๋ฅธ ๋ณ€์ˆ˜์— ๋‹ด์„ ์ˆ˜ ์žˆ๋‹ค.
์‚ฌ. bool cv::imwrite(String filename, Mat savemat, [int option]) - ์˜์ƒ์„ ๋””์Šคํฌ์— ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜
ex) cv::imwrite("output.png", result);
- ์ง€์›ํ•˜๋Š” ํฌ๋งท์€ bmp, jpg, tiff, png ๋“ฑ๋“ฑ.
- ์ƒ๋Œ€์œ„์น˜์˜ ํ˜„์žฌ์œ„์น˜๋Š” .cpp ํŒŒ์ผ์˜ ์œ„์น˜์ด๋ฉฐ ํ™•์žฅ์ž๋„ ํฌํ•จํ•ด์•ผํ•œ๋‹ค.
- ์ ˆ๋Œ€์œ„์น˜๋Š” "D:\image\test.jpg" ์ด๋Ÿฐ์‹์œผ๋กœ ํ‘œํ˜„
- [์˜ต์…˜]
๊ทธ ์™ธ ๋” ์ž์„ธํ•œ ์˜ต์…˜๊ณผ ๋‚ด์šฉ.
IMWRITE_JPEG_QUALITY = 1, //!< For JPEG, it can be a quality from 0 to 100 (the higher is the better). Default value is 95.
IMWRITE_JPEG_PROGRESSIVE = 2, //!< Enable JPEG features, 0 or 1, default is False.
IMWRITE_JPEG_OPTIMIZE = 3, //!< Enable JPEG features, 0 or 1, default is False.
IMWRITE_JPEG_RST_INTERVAL = 4, //!< JPEG restart interval, 0 - 65535, default is 0 - no restart.
IMWRITE_JPEG_LUMA_QUALITY = 5, //!< Separate luma quality level, 0 - 100, default is 0 - don't use.
IMWRITE_JPEG_CHROMA_QUALITY = 6, //!< Separate chroma quality level, 0 - 100, default is 0 - don't use.
IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). Default value is 1 (best speed setting).
IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE.
IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0.
IMWRITE_PXM_BINARY = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1.
IMWRITE_EXR_TYPE = (3 << 4) + 0, /* 48 */ //!< override EXR storage type (FLOAT (FP32) is default)
IMWRITE_WEBP_QUALITY = 64, //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used.
IMWRITE_PAM_TUPLETYPE = 128,//!< For PAM, sets the TUPLETYPE field to the corresponding string value that is defined for the format
์•„. cv::setMouseCallback(String windowname, cv::MouseCallback callbackfunctionname, void *userdata) - ์˜์ƒ ์œ„์— ๋งˆ์šฐ์Šค ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ด๋ฒคํŠธ ํ•จ์ˆ˜
ex) void onMouse(int event, int x, int y, int flags, void* param) {
cv::Mat *im = reinterpret_cast<cv::Mat*>(param);
switch (event)
{
case CV_EVENT_LBUTTONDOWN:
std::cout << "at (" << x << ", " << y << ") value is: " << static_cast<int>(im->at<uchar>(cv::Point(x, y))) << std::endl;
break;
}
}
... //...์€ ์ƒ๋žต์„ ์˜๋ฏธ ์œ„์— ์ฝœ๋ฐฑํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์˜ ํ˜•ํƒœ๋กœ ๋งŒ๋“ค์–ด๋†“๊ณ  ์จ์•ผํ•œ๋‹ค.
cv::setMouseCallback("Original Image", onMouse, reinterpret_cast<void*>(&image));
- onMouse ์‹œ๊ทธ๋‹ˆ์ฒ˜์˜ ์ฒซ๋ฒˆ์งธ ์ธ์ž๋Š” ์ด๋ฒคํŠธ ํƒ€์ž…, x, y๋Š” ๋งˆ์šฐ์Šค ์ขŒํ‘œ, flags๋Š” ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €๋Š”์ง€ ๊ฒฐ์ •ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๊ณ ,
๋งˆ์ง€๋ง‰์€ ํฌ์ธํ„ฐ ํ˜•ํƒœ์˜ ํ•จ์ˆ˜์— ์ถ”๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ณด๋‚ผ ๋•Œ ์‚ฌ์šฉ.
- event ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ CV_EVENT_MOUSEMOVE, CV_EVENT_MOUSELBUTTONUP, or DOWN, CV_EVENT_MOUSERBUTTONDOWN, or UP ๋“ฑ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
#include <opencv2/imgproc.hpp> ํ•„์š”ํ•œ ํ•จ์ˆ˜๋“ค (์ž, ์ฐจ, ํ•˜, ์ปค, ํ„ฐ, ํผ, ํ—ˆ, ๊ณ , ๋กœ, ์†Œ, ์˜ค, ์ดˆ, ๋“œ, ๋ฅด, ๋ฏ€, ๋ธŒ, ์Šค, ์œผ, ํŠธ, ํ”„, ํ, ๊ธฐ, ๋‹ˆ, ๋””, ๋ฆฌ, ๋ฏธ, ๋น„, ์‹œ)
์ž. void cv::circle(~~), ellipse(~~), line(~~), rectangle(~~) - ๋“œ๋กœ์ž‰ ํ•จ์ˆ˜
ex) cv::circle(image //์˜์ƒ, cv::Point(155,110) //์ค‘์‹ฌ์ , 65 //๋ฐ˜์ง€๋ฆ„, 0 //์ปฌ๋Ÿฌ(0์€ ๊ฒ€์€์ƒ‰), 3 //๊ตต๊ธฐ);
์ฐจ. void cv::putText(~~) - ํ…์ŠคํŒ… ํ•จ์ˆ˜
ex) cv::putText(image //์˜์ƒ, "This is a dog. " //๋‚ด์šฉ, cv::Point(40,200) //ํ…์ŠคํŠธ ์œ„์น˜, cv::FONT_HERSHEY_PLAIN //ํƒ€์ž…, 2.0 //ํฐํŠธ๋ฐฐ์œจ, 255 //์ƒ‰(ํฐ์ƒ‰), 2//๊ตต๊ธฐ);
์นด. int64 cv::getTickCount() - ์ปดํ“จํ„ฐ๋ฅผ ์‹œ์ž‘ํ•œ ์ตœ์ข…์‹œ๊ฐ„ ์ดํ›„์— ๋ฐœ์ƒํ•œ ํด๋ก ์‚ฌ์ดํด ์ˆ˜ ์ œ๊ณต. ์‹œ๊ฐ„ ์ธก์ •์‹œ(ํƒ€์ด๋จธ ์šฉ์œผ๋กœ) ์‚ฌ์šฉ.
ํƒ€. double cv::getTickFrequency() - 1์ดˆ๋‹น ์‚ฌ์ดํด ์ˆ˜๋ฅผ ์ œ๊ณต. ์—ญ์‹œ ์‹œ๊ฐ„๊ณ„์‚ฐ์„ ์œ„ํ•ด getTickCount()์™€ ๊ฐ™์ด ์“ด๋‹ค.
ex) const int64 start = cv::getTickCount();
colorReduce(image); //์‹œ๊ฐ„์ธก์ • ํ•  ํ•จ์ˆ˜ or ๋‚ด์šฉ๋“ค..
double duration = (cv::getTickCount() - start) / cv::getTickFrequency(); // ์ดˆ ๋‹จ์œ„์ธ ๊ฒฝ๊ณผ์‹œ๊ฐ„์„ ์•Œ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ms์ผ ๊ฒฝ์šฐ 1000.0์„ ๊ณฑํ•˜๋ฉด ๋จ.
ํŒŒ. template<type> cv::saturate_cast<type>(type value) - ํ•ด๋‹น ํƒ€์ž…์œผ๋กœ ์ˆ˜์น˜๋ฅผ ์ง€์ •ํ•œ๋‹ค. 0-255์ด๋ฉด ์Œ์ˆ˜ ๊ฐ’์€ 0, 255๋„˜์€ ๊ฐ’์€ 255๋กœ ์†Œ์ˆ˜์ ์€ ๊ฐ€๊นŒ์šด ์ •์ˆ˜๋กœ ๋ฐ˜์˜ฌ๋ฆผ.
ex) *output++ = cv::saturate_cast<uchar>(5 * current[i] - current[i - nchannals] - current[i + nchannals] - previous[i] - next[i]);
ํ•˜. void cv::filter2D(cv::InputArray src, cv::OutputArray dst, int dept, cv::InputArray kernel) - ํ–‰๋ ฌ์ปค๋„๋กœ ์˜์ƒ์„ ํ•„ํ„ฐ๋งํ•˜๋Š” ํ•จ์ˆ˜.
ex) cv::filter2D(image, result, image.depth(), kernel);
๊ฑฐ. void cv::add(cv::InputArray src1, cv::InputArray src2, cv::OutputArray rst, cv::InputArray mask = noArray()) - ์ด์ง„ ์‚ฐ์ˆ  ํ•จ์ˆ˜์ค‘์— ๋”ํ•˜๊ธฐ ๋‘ ์ด๋ฏธ์ง€์˜ ํ•ฉ์„ฑ์— ์‚ฌ์šฉํ•œ๋‹ค.
ex) cv::add(imageA,imageB,resultC);
ex) cv::add(imageA,cv::Scalar(k),resultC);
ex) cv::add(imageA,imageB,resultC,mask);
๋„ˆ. void cv::substract(cv::InputArray src1, cv::InputArray src2, cv::OutputArray rst, cv::InputArray mask = noArray()) - ์ด์ง„ ์‚ฐ์ˆ  ํ•จ์ˆ˜์ค‘์— ๋นผ๊ธฐ ๋‘ ์ด๋ฏธ์ง€์˜ ํ•ฉ์„ฑ์— ์‚ฌ์šฉํ•œ๋‹ค.
๋”. void cv::multiply(cv::InputArray src1, cv::InputArray src2, cv::OutputArray rst, cv::InputArray mask = noArray()) - ์ด์ง„ ์‚ฐ์ˆ  ํ•จ์ˆ˜์ค‘์— ๊ณฑํ•˜๊ธฐ ๋‘ ์ด๋ฏธ์ง€์˜ ํ•ฉ์„ฑ์— ์‚ฌ์šฉํ•œ๋‹ค.
๋Ÿฌ. void cv::divide(cv::InputArray src1, cv::InputArray src2, cv::OutputArray rst, cv::InputArray mask = noArray()) - ์ด์ง„ ์‚ฐ์ˆ  ํ•จ์ˆ˜์ค‘์— ๋‚˜๋ˆ„๊ธฐ ๋‘ ์ด๋ฏธ์ง€์˜ ํ•ฉ์„ฑ์— ์‚ฌ์šฉํ•œ๋‹ค.
๋จธ. void cv::absdiff(cv::InputArray src1, cv::InputArray src2, cv::OutputArray rst, cv::InputArray mask = noArray()) - ์ด์ง„ ์‚ฐ์ˆ  ํ•จ์ˆ˜์ค‘์— ์ฐจ์ด์˜ ์ ˆ๋Œ€๊ฐ’์„ ๊ตฌํ•œ๋‹ค. ๋‘ ์ด๋ฏธ์ง€์˜ ํ•ฉ์„ฑ์— ์‚ฌ์šฉํ•œ๋‹ค.
๋ฒ„. void cv::addWeighted(cv::InputArray src1, double alpha, cv::InputArray src2, double beta, double gamma, cv::OutputArray rst) - ๊ฐ€์ค‘์น˜๋ฅผ ๋‘๋ฉฐ addํ•˜๋Š” ๋ฐฉ์‹, ๊ฐ€์ค‘์น˜๋Š” 0์—์„œ 1๊นŒ์ง€๋‹ค.
ex) cv::addWeighted(imageA,k1,imageB,k2,k3,resultC);
์„œ. void scaleAdd(imageA, k, imageB, resultC) - ์Šค์นผ๋ผ ๊ฐ’์„ addํ•˜๋Š” ๋ฐฉ์‹, k์— ์Šค์นผ๋ผ ๊ฐ’
ex) cv::scaleAdd(imageA,k,imageB,resultC);
์–ด. void bitwise_and(cv::InputArray src1, cv::InputArray src2, cv::OutputArray rst, cv::InputArray mask = noArray()), bitwise_or, bitwise_xor, bitwise_not
- ๋น„ํŠธ๋ณ„ ์‚ฐ์ˆ  ํ•จ์ˆ˜๋“ค. ํ™”์†Œ๋ฅผ ์ด์ง„์œผ๋กœ ํ‘œํ˜„ํ•œ ๊ฐ ๋น„ํŠธ์— ์—ฐ์‚ฐ์ž๋ฅผ ์ ์šฉํ•œ๋‹ค.
์ €. cv::OutputArray cv::max(cv::InputArray src1, cv::InputArray src2), min - ์ตœ๋Œ€/์ตœ์†Œ ํ™”์†Œ๊ฐ’์„ ์ฐพ๋Š” ํ•จ์ˆ˜
์ฒ˜. cv::OutputArray cv::sqrt(cv::InputArray src), pow, abs, cuberoot, exp, log - ๊ทธ ์™ธ ์‚ฐ์ˆ ํ•จ์ˆ˜๋“ค
์ปค. void cv::remap(cv::InputArray src, cv::OutputArray dst, cv::InputArray map1, cv::InputArray map2, int interpolation) - ๋ฆฌ๋งตํ•‘ํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์›์‹œ์˜์ƒ, ๋ชฉ์ ์˜์ƒ, x๋งต, y๋งต, ๋ณด๊ฐ„๋ฐฉ๋ฒ• ์ธ์ž๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค.
ex) cv::remap(image, result, srcX, srcY, CV_INTER_LINEAR);
ํ„ฐ. double cv::threshold(cv::InputArray src, cv::OutputArray dst, double thresh, double maxval, int type) - ๋ชจ๋“ ํ™”์†Œ๋ฅผ ์ •ํ•ด๋†“์€ ๊ฒฝ๊ณ„๊ฐ’๊ณผ ๋น„๊ตํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์ผ๋ฐ˜ ๊ฒฝ๊ณ„ํ™” ๋ชจ๋“œ(cv::THRESH_BINARY)์—์„œ ๋ชจ๋“ ํ™”์†Œ๊ฐ€ ๊ฒฝ๊ณ„๊ฐ’๋ณด๋‹ค ํฌ๋ฉด ์ •์˜๋œ ์ตœ๋Œ“๊ฐ’์„ ํ• ๋‹นํ•˜๊ณ , ์ž‘์œผ๋ฉด 0์„ ํ• ๋‹นํ•œ๋‹ค.
- ๋ฐ˜์ „๋ชจ๋“œ(cv::THRESH_BINARY_INV) ๊ฒฝ๊ณ„๊ฐ’๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์œผ๋ฉด ์ตœ๋Œ“๊ฐ’์„ ํ• ๋‹นํ•˜๊ณ  cv::THRESH_TOZERO๋Š” ํ™”์†Œ๊ฐ€ ๊ฒฝ๊ณ„๊ฐ’๋ณด๋‹ค ํฌ๋ฉด ๋†”๋‘๊ณ , ์•„๋‹ˆ๋ฉด 0ํ• ๋‹น.. cv::THRESH_TOZERO_INV๋„ ์žˆ๋‹ค.
ex) cv::threshold(output, output, maxDist, 255, cv::THRESH_BINARY_INV);
ํผ. int cv::floodFill(cv::InputArray src, cv::Point seedPoint, cv::Scalar newVal, cv::Rect *rect=(cv::Rect*)0, cv::Scalar loDiff = cv::Scalar(), cv::Scalar upDiff = cv::Scalar(), int flags=4)
- ์ฃผ์–ด์ง„ ๋Œ€์ƒ ์ปฌ๋Ÿฌ์™€ ๋น„์Šทํ•œ ์ปฌ๋Ÿฌ๋ฅผ ๊ฐ–๋Š” ํ™”์†Œ๋ฅผ ์‹๋ณ„ํ•˜๋Š”๋ฐ ํ™”์†Œ์˜ ์ด์›ƒ์ƒํƒœ์— ๋”ฐ๋ฅธ๋‹ค.
ex) cv::floodFill(image, //์ž…๋ ฅ/๊ฒฐ๊ณผ ์˜์ƒ
cv::Point(100, 50), //์ดˆ๊ธฐ ์ 
cv::Scalar(255, 255, 255), //๋‹ค์‹œ ๊ทธ๋ฆฐ ์ปฌ๋Ÿฌ
(cv::Rect*)0, //๋‹ค์‹œ ๊ทธ๋ฆฐ ์ง‘ํ•ฉ์˜ ๊ฒฝ๊ณ„ ์‚ฌ๊ฐํ˜•
cv::Scalar(35, 35, 35), //๋‚ฎ์€ ์ฐจ์ด ๊ฒฝ๊ณ„๊ฐ’
cv::Scalar(35, 35, 35), //๋†’์€ ์ฐจ์ด ๊ฒฝ๊ณ„๊ฐ’
cv::FLOODFILL_FIXED_RANGE); //์‹œ๋“œ ํ™”์†Œ์™€ ๋น„๊ตํ•  ํ™”์†Œ
ํ—ˆ. void cv::cvtColor(cv::InputArray src, cv::OutputArray dst, int code) - ์ปฌ๋Ÿฌ ๋ณ€ํ™˜ํ•จ์ˆ˜๋กœ ๋‹ค์–‘ํ•œ ์ปฌ๋Ÿฌ๊ณต๊ฐ„์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. Lab์นผ๋Ÿฌ๊ณต๊ฐ„์„ ์ด์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. RGB2GRAY ์ด๋Ÿฐ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ๋„ ์žˆ๋‹ค.
ex) cv::cvtColor(image, converted, CV_BGR2Lab);
๊ณ . void grabCut(cv::InputArray img, cv::InputOutputArray mask, cv::Rect rect, cv::InputOutputArray bgdModel, cv::InputOutputArray fgdModel, int iterCount, int mode)
- ๊ทธ๋žฉ์ปท ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํ•จ์ˆ˜๋กœ ์ •์ง€ ์˜์ƒ์—์„œ ์ „๊ฒฝ ๊ฐ์ฒด๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๊ธฐ์— ๊ฐ€์žฅ ์ข‹์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜.
- ์ž…๋ ฅ/๊ฒฐ๊ณผ ๋ถ„ํ•  ์˜์ƒ์€ 4๊ฐ€์ง€ ๊ฐ’ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ฐ–๊ฒŒ ๋œ๋‹ค.
cv::GC_BGD = 0 ๋ฐฐ๊ฒฝ์— ๋ถ„๋ช…ํžˆ ์†ํ•˜๋Š” ํ™”์†Œ(์˜ˆ๋ฅผ๋“ค์–ด ์‚ฌ๊ฐํ˜• ๋ฐ–์— ์žˆ๋Š” ํ™”์†Œ),
cv::GC_FGD = 1 ์ „๊ฒฝ์— ๋ถ„๋ช…ํžˆ ์†ํ•˜๋Š” ํ™”์†Œ(์˜ˆ๋ฅผ๋“ค์–ด ์•„๋ž˜ ์˜ˆ์ œ์—๋Š” ์—†์Œ),
cv::GC_PR_BGD = 2 ์•„๋งˆ๋„ ๋ฐฐ๊ฒฝ์— ์†ํ•  ๋“ฏํ•œ ํ™”์†Œ์— ๋Œ€ํ•œ ๊ฐ’
cv::GC_PR_FGD = 3 ์•„๋งˆ๋„ ์ „๊ฒฝ์— ์†ํ•  ๋“ฏํ•œ ํ™”์†Œ์— ๋Œ€ํ•œ ๊ฐ’(์˜ˆ๋ฅผ๋“ค์–ด ์•„๋ž˜ ์˜ˆ์ œ์—์„œ ์‚ฌ๊ฐํ˜• ๋‚ด๋ถ€์— ์žˆ๋Š” ํ™”์†Œ๋ฅผ ์–ป๊ธฐ ์œ„ํ•œ ์ดˆ๊ธฐ๊ฐ’)
ex) cv::Mat result; //๋ถ„ํ•  (๊ฐ€๋Šฅํ•œ ๊ฐ’์€ 4๊ฐœ)
cv::Mat bgModel, fgModel; //๋ชจ๋ธ (๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ)
cv::grabCut(image, //์ž…๋ ฅ ์˜์ƒ
result, //๋ถ„ํ•  ๊ฒฐ๊ณผ
rectangle, //์ „๊ฒฝ์„ ํฌํ•จํ•œ ์‚ฌ๊ฐํ˜•
bgModel, fgModel, //๋ชจ๋ธ
5, //๋ฐ˜๋ณต ํšŸ์ˆ˜
cv::GC_INIT_WITH_RECT); //์‚ฌ๊ฐํ˜• ์‚ฌ์šฉ
๋…ธ. void compare(cv::InputArray src1, cv::InputArray src2, cv::OutputArray dst, int cmpop) - ๋‘ ๊ฐœ์˜ ์ž…๋ ฅ๊ฐ’์˜ scalar ๊ฐ’์„ ๋น„๊ตํ•˜๋Š” ํ•จ์ˆ˜๋กœ ๋งŒ์กฑํ•˜๋Š” src1์˜ ํ™”์†Œ๋งŒ dst๊ฒฐ๊ณผ๊ฐ’์œผ๋กœ ๋ฝ‘์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
ex) cv::compare(result, cv::GC_PR_FGD, result, cv::CMP_EQ);
๋„. void cv::split(cv::InputArray m, cv::OutputArrayOfArrays mv), void merge(cv::InputArrayOfArrays mv, cv::OutputArray dst) - ์˜์ƒ ์ฑ„๋„ ๋ถ„๋ฆฌ/๊ฒฐํ•ฉ, ๊ฐ ์ฑ„๋„์„ ๋”ฐ๋กœ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
- ์‚ฌ์šฉ๋ฒ•์€ void cv::split(๋ถ„๋ฆฌํ• , ๋ถ„๋ฆฌ๋œ) ๊ณผ cv::merge(ํ•ฉ์น ,ํ•ฉ์ณ์ง„)๋กœ ๊ฐ€๋Šฅํ•˜๋‹ค.
ex) // 3๊ฐœ์˜ Mat๋กœ ์ด๋ค„์ง„ Vector ์„ ์–ธ
std::vector<cv::Mat> planes;
// 3์ฑ„๋„ ์ด๋ฏธ์ง€์˜ ์ฑ„๋„์„ ๋ชจ๋‘ ๋‚˜๋ˆ  3๊ฐœ์˜ ์ด๋ฏธ์ง€๋กœ splitํ•จ์ˆ˜
cv::split(image1, planes);
// ๋ธ”๋ฃจ์ฑ„๋„์— ADDํ•˜๊ธฐ
planes[0] += image2;
// ๋‹ค์‹œ 3์ฑ„๋„ ํ•ฉ์ณ์„œ ํ•˜๋‚˜์˜ 3์ฑ„๋„ ์ด๋ฏธ์ง€๋กœ
cv::merge(planes, result);
๋กœ. void calcHist(const cv::Mat *images, int nimages, const int *channels, cv::InputArray mask, cv::OutputArray hist, int dims, const int *histSize, const float **ranges)
- ์ž„์˜ ํ™”์†Œ ๊ฐ’ ํƒ€์ž…๊ณผ ๋ฒ”์œ„๋ฅผ ๊ฐ–๋Š” ๋‹ค์ฑ„๋„ ์˜์ƒ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋Š” ์ผ๋ฐ˜์ ์ธ ํ•จ์ˆ˜์ด๋‹ค.
ex) //ํžˆ์Šคํ† ๊ทธ๋žจ ๊ณ„์‚ฐํ•˜๊ธฐ
cv::calcHist(&image,
1, //๋‹จ์ผ ์˜์ƒ ํžˆ์Šคํ† ๊ทธ๋žจ๋งŒ
channels, //๋Œ€์ƒ ์ฑ„๋„
cv::Mat(), //๋งˆ์Šคํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
hist, //๊ฒฐ๊ณผ ํžˆ์Šคํ† ๊ทธ๋žจ
3, //3D ํžˆ์Šคํ† ๊ทธ๋žจ
histSize, //๋นˆ ๊ฐœ์ˆ˜
ranges //ํ™”์†Œ ๊ฐ’์˜ ๋ฒ”์œ„
);
๋ชจ. void minMaxLoc(cv::InputArray src, double *minVal, double *maxVal=(double *)0, cv::Point *minLoc = (cv::Point *)0, cv::Point *maxLoc = (cv::Point *)0, cv::InputArray mask = noArray())
- ๋ฐฐ์—ด ๋‚ด์—์„œ ์ตœ๋Œ€, ์ตœ์†Œ๊ฐ’์„ ์ฐพ๋Š” ํ•จ์ˆ˜ ๋ฉ€ํ‹ฐ ์ฑ„๋„ ๋ฐฐ์—ด์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค.
ex) //์ตœ์†Œ ์ตœ๋Œ€ ๋นˆ ๊ฐ’ ์–ป๊ธฐ
double maxVal = 0;
double minVal = 0;
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
๋ณด. void cv::LUT(cv::InputArray src, cv::InputArray lut, cv::OutputArray dst) - LUT๋Š” ์ „์ฒด์ ์œผ๋กœ ๋ณ€ํ™˜์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์ด ํ•จ์ˆ˜๋Š” ๊ฐ„๋‹จํ•œ ์ผ๋Œ€์ผ(๋˜๋Š” ๋‹ค๋Œ€์ผ) ํ•จ์ˆ˜๋กœ์„œ ํ™”์†Œ ๊ฐ’์„ ์ƒˆ๋กœ์šด ํ™”์†Œ ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
- ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ๋ชจ๋“  ํ™”์†Œ์˜ ๋ช…๋„๋ฅผ ์ฃผ์–ด์ง„ ์ƒˆ๋กœ์šด ๋ช…๋„ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
ex) //๋ฃฉ์—… ํ…Œ์ด๋ธ” ์ ์šฉํ•˜๊ธฐ
cv::LUT(image, lookup, result);
์†Œ. int cvRound(double value) - ๋ฐ˜์˜ฌ๋ฆผ ์‹œํ‚ค๋Š” cv imgproc์˜ ํ•จ์ˆ˜
ex) lookup.at<uchar>(i) = cvRound(255.0*(i - imin) / (imax - imin));
์˜ค. void cv::equalizeHist(cv::InputArray src, cv::OutputArray dst) - ๊ทธ๋ ˆ์ด ์Šค์ผ€์ผ ์˜์ƒ์˜ ํžˆ์Šคํ† ๊ทธ๋žจ์„ ํ‰ํ™œํ™” ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜.
ex) cv::equalizeHist(image, result);
์กฐ. void cv::normalize(cv::InputArray src, cv::InputOutputArray dst, double alpha = (1.0)) - ๋ฐฐ์—ด์„ ์ •๊ทœํ™”ํ•˜๋Š” ํ•จ์ˆ˜
ex) cv::normalize(h, histogram, 1.0);
์ดˆ. void cv::calcBackProject(const cv::Mat *images, int nimages, const int *channels, cv::InputArray hist, cv::OutputArray backProject, const float **ranges, double scale = (1.0))
- ์ž…๋ ฅ ์˜์ƒ์˜ ๊ฐ ํ™”์†Œ๋ฅผ ์ •๊ทœํ™” ๋œ ํžˆ์Šคํ† ๊ทธ๋žจ์—์„œ ์ฝ์–ด ๋“ค์ธ ๋Œ€์‘ํ•˜๋Š” ํ™•๋ฅ  ๊ฐ’์œผ๋กœ ๋ฐ”๊ฟ” ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๊ตฌ์„ฑํ•œ ํ›„ ์—ญํˆฌ์˜ํ•˜๋Š” ํ•จ์ˆ˜.
ex) cv::calcBackProject(&image,
1, //ํ•œ ๋ฒˆ์— ์˜์ƒ 1๊ฐœ๋งŒ ์‚ฌ์šฉ
channels, //์˜์ƒ ์ฑ„๋„์— ์†ํ•˜๋Š” ํžˆ์Šคํ† ๊ทธ๋žจ ์ฐจ์›์„ ์ง€์ •ํ•œ ๋ฐฑํ„ฐ
histogram, //์‚ฌ์šฉํ•  ํžˆ์Šคํ† ๊ทธ๋žจ
result, //์—ญํˆฌ์˜ ์˜์ƒ
ranges, //์ฐจ์›๋‹น ๊ฐ’์˜ ๋ฒ”์œ„
255.0 //ํ™•๋ฅ  ๊ฐ’์˜ 1์„ 255๋กœ ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•ด ์„ ํƒํ•œ ์žฌ์กฐ์ • ์ธ์ž
);
์ฝ”. cv::SparseMat - ํฌ์†Œํ™”ํ•œ ํ–‰๋ ฌ์ด๋‹ค.
-Mat์™€ ๊ฑฐ์˜ ๋น„์Šทํ•˜๋‹ค. ๊ณผ๋„ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋ชจ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
ex) cv::SparseMat hist(3, //์ฐจ์›์˜ ๊ฐœ์ˆ˜
histSize, //๊ฐ ์ฐจ์›์˜ ํฌ๊ธฐ
CV_32F);
ํ† . cv::TermCriteria - ๋ฐ˜๋ณต์ ์ธ ์•Œ๊ณ  ๋ฆฌ์ฆ˜์„ ์œ„ํ•œ ์‹œํ•œ์ ์ธ ํ•œ๊ณ„๋ฅผ ์ •์˜ํ•˜๋Š” ํด๋ž˜์Šค์ด๋‹ค. meanShift์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ ์‚ฌ์šฉํ•œ๋‹ค.
ex) cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS,
10, //์ตœ๋Œ€ 10ํšŒ ๋ฐ˜๋ณต
1); //๋˜๋Š” ์ค‘์‹ฌ ์œ„์น˜ ๋ณ€ํ™”๊ฐ€ 1ํ”ฝ์…€ ๋ฏธ๋งŒ์ด ๋  ๋•Œ๊นŒ์ง€
cout << "meanshift= " << cv::meanShift(result, rect, criteria) << endl;
#include <opencv2/video/tracking.hpp> ๊ฐ€ ํ•„์š”ํ•œ ํ•จ์ˆ˜๋“ค (ํฌ)
ํฌ. int cv::meanShift(cv::InputArray probImage, cv::Rect &window, cv::TermCriteria criteria) - ํ‰๊ท  ์ด๋™ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฐฑํˆฌ์˜์˜์ƒ์œผ๋กœ๋ถ€ํ„ฐ ๊ฐ์ฒด๋ฅผ ์ฐพ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜
- opencv2/video/tracking.hpp์•ˆ์— ๋“ค์–ด์žˆ๋‹ค.
ํ™•๋ฅ  ํ•จ์ˆ˜์˜ ์ง€์—ญ ์ตœ๋Œ€์น˜(local maxima)๊ฐ€ ์žˆ๋Š” ์œ„์น˜๋ฅผ ์ฐพ๋Š” ๋ฐ˜๋ณต ๊ณ„์‚ฐ๋ฒ•(iterative procedure)์ด๋‹ค. ๋ฏธ๋ฆฌ ์ •์˜๋œ ์œˆ๋„์šฐ ์•ˆ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์ ์˜ ์ค‘์‹ฌ(centroid)์ด๋‚˜ ๊ฐ€์ค‘ ํ‰๊ท (weighted mean)์„ ์ฐพ๋Š”๋ฐฉ์‹์œผ๋กœ
์ˆ˜ํ–‰ํ•œ๋‹ค. ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์œˆ๋„์šฐ ์ค‘์•™(window center)์„ ์ค‘์‹ฌ ์œ„์น˜๋กœ ์˜ฎ๊ธด ํ›„ ์œˆ๋„์šฐ์˜ ์ค‘์•™์ด ์•ˆ์ •์ (stable point)์œผ๋กœ ์ˆ˜๋ ดํ•  ๋•Œ๊นŒ์ง€ ํ•ด๋‹น ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•œ๋‹ค. OpenCV์˜ ๊ตฌํ˜„๋ถ€์—์„œ 2๊ฐœ์˜ ์ค‘์ง€๊ธฐ์ค€(stopping criteria)์„ ์ •์˜ํ•˜๋ฉฐ,
๋ฐ˜๋ณต ์ตœ๋Œ€ ํšŸ์ˆ˜(MAX_ITER), ๊ทธ๋ฆฌ๊ณ  ์•ˆ์ •์ ์— ์ˆ˜๋ ด๋˜๋„๋ก ๊ณ ๋ ค๋ผ์•ผ ํ•˜๋Š” ์œ„์น˜์˜ ์•„๋ž˜์ธ ์œˆ๋„์šฐ ์ค‘์•™ ๋ณ€์œ„ ๊ฐ’(EPS)์ด๋‹ค. 2๊ฐœ์˜ ์ค‘์ง€ ๊ธฐ์ค€์€ cv::TermCriteria์ธ์Šคํ„ด์Šค์— ์ €์žฅ๋œ๋‹ค. cv::meanShiftํ•จ์ˆ˜๋Š” ์ˆ˜ํ–‰ํ–ˆ๋˜ ๋ฐ˜๋ณตํšŸ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
ex) // initial window position
cv::rectangle(image, rect, cv::Scalar(0,0,255));
// search objet with mean shift
cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS,
10, // iterate max 10 times
1); // or until the change in centroid position is less than 1px
cout << "meanshift= " << cv::meanShift(result,rect,criteria) << endl;
// draw output window
cv::rectangle(image, rect, cv::Scalar(0,255,0));
ํ˜ธ. double cv::compareHist(cv::InputArray H1, cv::InputArray H2, int method) - ๋‘ ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๋น„๊ตํ•ด ์ˆ˜์น˜๋กœ ๋‚˜ํƒ€๋‚ด๋Š” ํ•จ์ˆ˜.
ex) //๋‘ BGR ํžˆ์Šคํ† ๊ทธ๋žจ์„ ์‚ฌ์šฉํ•ด ์˜์ƒ ๋น„๊ต
double compare(const cv::Mat& image)
{
inputH = hist.getHistogram(image);
//๊ต์ฐจ์ ์„ ์ด์šฉํ•œ ํžˆ์Šคํ† ๊ทธ๋žจ ๋น„๊ต
return cv::compareHist(refH, inputH, cv::HISTCMP_INTERSECT);
}
ํ”Œ๋ž˜๊ทธ ์ข…๋ฅ˜(method ๋งค๊ฐœ๋ณ€์ˆ˜)๋Š”
- HISTCMP_INTERSECT : ๊ฐ ํžˆ์Šคํ† ๊ทธ๋žจ์—์„œ ๊ฐ ๋นˆ๋งˆ๋‹ค ๋‘ ๊ฐ’์„ ๋‹จ์ˆœํ•˜๊ฒŒ ๋น„๊ตํ•œ ํ›„ ์ตœ์†Ÿ๊ฐ’์„ ์œ ์ง€ํ•œ๋‹ค. ์œ ์‚ฌ๋„ ์ธก์ •์€ ์ด๋Ÿฐ ์ตœ์†Ÿ๊ฐ’์˜ ํ•ฉ์ด ๋œ๋‹ค. ๋‘ ์˜์ƒ์ด ์ปฌ๋Ÿฌ๊ฐ€ ์—†๋Š” ํžˆ์Šคํ† ๊ทธ๋žจ์„ ๊ฐ–๋Š”๋‹ค๋ฉด 0์ธ ์ธํ„ฐ์„น์…˜ ๊ฐ’์„ ์–ป๋Š” ๋ฐ˜๋ฉด, ๋‘ ํžˆ์Šคํ† ๊ทธ๋žจ์ด ๋™์ผํ•˜๋‹ค๋ฉด ํ™”์†Œ์˜ ์ด ๊ฐœ์ˆ˜์™€ ๊ฐ™์€ ๊ฐ’์„ ์–ป๋Š”๋‹ค.
- HISTCMP_CHISQR : ๋นˆ ๊ฐ„์˜ ์ •๊ทœํ™”๋œ ์ œ๊ณฑ ์ฐจ๋ฅผ ํ•ฉํ•˜๋Š” ์นด์ด ์ œ๊ณฑ(Chi-Square)์ธก์ •
- HISTCMP_CORREL : ์‹ ํ˜ธ์ฒ˜๋ฆฌ์—์„œ ๋‘ ์‹ ํ˜ธ ๊ฐ„์˜ ์œ ์‚ฌ๋„๋ฅผ ์ธก์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์ •๊ทœํ™”๋œ ์ƒํ˜ธ ์ƒ๊ด€ ์—ฐ์‚ฐ์ž์— ๊ธฐ๋ฐ˜์„ ๋‘๊ณ  ์žˆ๋Š” ์ƒ๊ด€๊ด€๊ณ„(Corrleation) ๋ฐฉ๋ฒ•
- HISTCMP_BHATTACHARYYA : ํ†ต๊ณ„์—์„œ ๋‘ ํ™•๋ฅ  ๋ถ„ํฌ ๊ฐ„์˜ ์œ ์‚ฌ๋„๋ฅผ ์ถ”์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ฐ”ํƒ€์ฐจ๋ฅด์•ผ(Bhattacharyya) ์ธก์ •์ด ์žˆ๋‹ค.
๊ทธ. void integral(cv::InputArray src, cv::OutputArray sum, int sdepth = -1) - ์˜์ƒ์„ ์ ๋ถ„ ๊ณ„์‚ฐํ• ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.
ex) cv::Mat integralImage;
cv::integral(image, integralImage, CV_32S);
๋А. void cv::transpose(cv::InputArray src, cv::OutputArray dst) - ์‹œ๊ณ„๋ฐฉํ–ฅ์œผ๋กœ 90๋„ ๋Œ๋ฆฐ๋‹ค.
ex) cv::transpose(image, image);
๋“œ. void cv::boxFilter(cv::InputArray src, cv::OutputArray dst, int ddepth, cv::Size ksize, cv::Point anchor) - ๊ณ„์‚ฐ ์šฉ๋„๋‚˜ ํ๋ ค์ง€๊ฒŒ ํ•˜๋Š” ์šฉ๋„๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.
ex) cv::boxFilter(image, filtered, CV_8U, cv::Size(blockSize, blockSize));
๋ฅด. adaptiveThreshold(cv::InputArray src, cv::OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C) - ์ ์‘์  ๊ฒฝ๊ณ„๊ฐ’์„ ์ ์šฉ์‹œํ‚ค๋Š” ํ•จ์ˆ˜, ๊ฐ„๋‹จํ•˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๊ฒŒ ์ข‹๋‹ค.
ex) cv::adaptiveThreshold(image, //์ž…๋ ฅ ์˜์ƒ
binaryAdaptive, //์ถœ๋ ฅ ์ด์ง„์˜์ƒ
255, //์ถœ๋ ฅ ์ตœ๋Œ€๊ฐ’
cv::ADAPTIVE_THRESH_MEAN_C, //์ ์‘ํ™” ๋ฐฉ๋ฒ•
cv::THRESH_BINARY, //๊ฒฝ๊ณ„ํ™” ์ข…๋ฅ˜
blockSize, //๋ธ”๋Ÿญ์˜ ์‚ฌ์ด์ฆˆ
threshold); //๊ฒฝ๊ณ„๊ฐ’ ์‚ฌ์šฉ
๋ฏ€. void cv::erode(cv::InputArray src, cv::OutputArray dst, cv::InputArray kernel, cv::Point anchor, int iterations) - ์˜์ƒ์„ ๊ตฌ์กฐ์š”์†Œ(SE)๋กœ ์นจ์‹์‹œํ‚ค๋Š” ํ•„ํ„ฐ ํ•จ์ˆ˜. ํ˜„์žฌ ํ™”์†Œ๋ฅผ ์ •์˜๋œ ํ™”์†Œ ์ง‘ํ•ฉ์—์„œ ์ฐพ์€ ์ตœ์†Œ ํ™”์†Œ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
ex) cv::erode(image, eroded, cv::Mat());
ex) //๋” ํฐ ๊ตฌ์กฐ์š”์†Œ(SE)๋กœ ์˜์ƒ ์นจ์‹
//1์„ ๋ชจ๋‘ ํฌํ•จํ•˜๋Š” 7*7 ํ–‰๋ ฌ ์ƒ์„ฑ
cv::Mat element(7, 7, CV_8U, cv::Scalar(1));
//๊ตฌ์กฐ์š”์†Œ(SE)๋กœ ์˜์ƒ ์นจ์‹
cv::erode(image, eroded, element);
ex) //์˜์ƒ์„ ์„ธ ๋ฒˆ ์นจ์‹
cv::erode(image, eroded, cv::Mat(), cv::Point(-1, -1), 3);
๋ธŒ. void cv::dilate(cv::InputArray src, cv::OutputArray dst, cv::InputArray kernel, cv::Point anchor, int iterations) - ์˜์ƒ์„ ๊ตฌ์กฐ์š”์†Œ(SE)๋กœ ํŒฝ์ฐฝ์‹œํ‚ค๋Š” ํ•„ํ„ฐ ํ•จ์ˆ˜. ํ˜„์žฌ ํ™”์†Œ๋ฅผ ์ •์˜๋œ ํ™”์†Œ ์ง‘ํ•ฉ์—์„œ ์ฐพ์€ ์ตœ๋Œ€ ํ™”์†Œ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
ex) cv::dilate(image, dilated, cv::Mat());
์Šค. void cv::morphologyEx(cv::InputArray src, cv::OutputArray dst, int op, cv::InputArray kernel, cv:Point anchor, int iterations) - ํ˜•ํƒœํ•™์  ๋ณ€ํ˜•(์นจ์‹, ํŒฝ์ฐฝ)์„ ๋ณด์™„ํ•œ๋‹ค. ์—ด๋ฆผ, ๋‹ซํž˜, ๊ธฐ์šธ๊ธฐ, ํƒ‘ํ–‡ ๋“ฑ ํ•„ํ„ฐ ์ ์šฉ์— ์‚ฌ์šฉ๋œ๋‹ค.
ex) cv::Mat element5(5, 5, CV_8U, cv::Scalar(1));
cv::Mat closed;
cv::morphologyEx(image, closed, //์ž…๋ ฅ ์˜์ƒ๊ณผ ๊ฒฐ๊ณผ ์˜์ƒ
cv::MORPH_CLOSE, //์—ฐ์‚ฐ์ž ์ฝ”๋“œ
element5); //๊ตฌ์กฐ ์š”์†Œ(SE)
์œผ. void cv::watershed(cv::InputArray image, cv::InputOutputArray markers) - ์›Œํ„ฐ์‰๋“œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด ๋งˆ์ปค ๊ธฐ๋ฐ˜ ์˜์ƒ ๋ถ„ํ• ํ•˜๋Š” ํ•จ์ˆ˜, ๋™์งˆ ์˜์—ญ ๋ถ„ํ• ์— ์‚ฌ์šฉ๋œ๋‹ค.
ex) //์›Œํ„ฐ์‰๋“œ ์ ์šฉ
cv::watershed(image, markers);
#include <opencv2/feature2D.hpp> ํ•„์š”ํ•œ ํ•จ์ˆ˜๋“ค (์ฆˆ)
์ฆˆ. cv::MSER - ์ถ”์ƒ ํด๋ž˜์Šค MSER(Maximally Stable External Region) ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ณ„์‚ฐํ•˜๋Š” ํด๋ž˜์Šค. - ์˜๋ฏธ์žˆ๋Š” ์˜์—ญ์„ ์ถ”์ถœํ•˜๊ธฐ ์œ„ํ•ด ์นจ์ˆ˜ ์œ ์ถ”๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
- create(int _delta, int_min_area, int_max_area) - MSER ๊ฒ€์ถœ๊ธฐ ์ƒ์„ฑ ํ•จ์ˆ˜
- detectRegions(cv::InputArray image, std::vector<std::vector<cv::Point>> &msers, std::vector<cv::Rect> &bboxes) - MSER ํŠน์ง• ๊ฒ€์ถœํ•˜๋Š” ํ•จ์ˆ˜()
-
ex) //๊ธฐ๋ณธ MSER ๊ฒ€์ถœ๊ธฐ
cv::Ptr<cv::MSER> ptrMSER = cv::MSER::create(5, //์ง€์—ญ์„ ๊ฒ€์ถœํ•˜๊ธฐ ์œ„ํ•œ ๋ธํƒ€ ๊ฐ’
200, //์ตœ์†Œ ํ—ˆ์šฉ ๋ฉด์ 
2000); //์ตœ๋Œ€ ํ—ˆ์šฉ ๋ฉด์ 
//์  ์ง‘ํ•ฉ์˜ ๋ฐฑํ„ฐ
std::vector<std::vector<cv::Point> > points;
//์ง์‚ฌ๊ฐํ˜•์˜ ๋ฐฑํ„ฐ
std::vector<cv::Rect> rects;
//MSER ํŠน์ง• ๊ฒ€์ถœ
ptrMSER->detectRegions(image, points, rects);
std::cout << points.size() << " MSERs detected" << std::endl;
//ํฐ์ƒ‰ ์˜์ƒ ์ƒ์„ฑ
cv::Mat output(image.size(), CV_8UC3);
output = cv::Scalar(255, 255, 255);
//OpenCV ๋‚œ์ˆ˜ ๋ฐœ์ƒ๊ธฐ(random number generator)
cv::RNG rng;
//MSER์˜ ์ƒ‰์˜์—ญ ํ‘œ์‹œ
//๊ฐ๊ฐ ๊ฒ€์ถœ๋œ ํŠน์ง•์— ๋Œ€ํ•ด ๊ฐ€์žฅ ํฐ MSER๋ถ€ํ„ฐ ์—ญ์ˆœ์„œ๋กœ ํ‘œ์‹œ
for (std::vector<std::vector<cv::Point>>::reverse_iterator it = points.rbegin(); it != points.rend(); ++it)
{
//์ž„์˜ ์ƒ‰ ์ƒ์„ฑ
cv::Vec3b c(rng.uniform(0, 254),
rng.uniform(0, 254),
rng.uniform(0, 254));
std::cout << "MSER size= " << it->size() << std::endl;
//MSER ์ง‘ํ•ฉ์˜ ๊ฐ ์ ์— ๋Œ€ํ•ด
for (std::vector<cv::Point>::iterator itPts = it->begin(); itPts != it->end(); ++itPts)
{
//MSER ํ™”์†Œ๋“ค์„ ๋ฎ์–ด ์“ฐ์ง€ ์•Š์Œ
if (output.at<cv::Vec3b>(*itPts)[0] == 255)
{
output.at<cv::Vec3b>(*itPts) = c;
}
}
}
cv::namedWindow("MSER point sets");
cv::imshow("MSER point sets",output);
์ธ . cv::RNG - ๋žœ๋ค ์ˆซ์ž ์ƒ์„ฑ๊ธฐ ํด๋ž˜์Šค ๊ฐ์ฒด ์ƒ์„ฑ ํ›„ .uniform(์ˆซ์ž๋ฒ”์œ„,~)๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
ex) //OpenCV ๋‚œ์ˆ˜ ๋ฐœ์ƒ๊ธฐ(random number generator)
cv::RNG rng;
//MSER์˜ ์ƒ‰์˜์—ญ ํ‘œ์‹œ
//๊ฐ๊ฐ ๊ฒ€์ถœ๋œ ํŠน์ง•์— ๋Œ€ํ•ด ๊ฐ€์žฅ ํฐ MSER๋ถ€ํ„ฐ ์—ญ์ˆœ์„œ๋กœ ํ‘œ์‹œ
for (std::vector<std::vector<cv::Point>>::reverse_iterator it = points.rbegin(); it != points.rend(); ++it)
{
//์ž„์˜ ์ƒ‰ ์ƒ์„ฑ
cv::Vec3b c(rng.uniform(0, 254), rng.uniform(0, 254), rng.uniform(0, 254));
ํฌ. cv::RotatedRect - ํšŒ์ „๋œ ์‚ฌ๊ฐํ˜•์„ ํ‘œํ˜„ํ•˜๋Š” ํด๋ž˜์Šค
ex) //๊ฒฝ๊ณ„ ์‚ฌ๊ฐํ˜• ์ถ”์ถœ
cv::RotatedRect rr = cv::minAreaRect(*it);
ํŠธ. cv::RotatedRect cv::minAreaRect(cv::InputArray points) - ํšŒ์ „๋œ ์‚ฌ๊ฐํ˜•์„ ๋‘˜๋Ÿฌ์‹ธ๋Š” ์˜์—ญ ์ตœ์†Œ ์ง์‚ฌ๊ฐํ˜•์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
ex) //๊ฒฝ๊ณ„ ์‚ฌ๊ฐํ˜• ์ถ”์ถœ
cv::RotatedRect rr = cv::minAreaRect(*it);
ํ”„. void blur(cv::InputArray src, cv::OutputArray dst, cv::Size ksize, cv::Point anchor = cv::Point(-1,-1) - ๋ธ”๋Ÿฌํšจ๊ณผ ์ฃผ๋Š” ํ•จ์ˆ˜
ex) cv::blur(image, result, cv::Size(9, 9));
ํ. void GaussianBlur(cv::InputArray src, cv::OutputArray dst, cv::Size ksize, cv::Point anchor, double sigmaX) - ๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌํšจ๊ณผ ์ฃผ๋Š” ํ•จ์ˆ˜.
ex) cv::GaussianBlur(image, result,
cv::Size(5, 5), //ํ•„ํ„ฐ์˜ ํฌ๊ธฐ
1.5); //๊ฐ€์šฐ์‹œ์•ˆ์˜ ๋ชจ์–‘์„ ์กฐ์ •ํ•˜๋Š” ๊ณ„์ˆ˜
๊ธฐ. cv::Mat cv::getGaussianKernel(int ksize, double sigma, int ktype) - ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ์˜ ๊ณ„์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
ex) //๊ฐ€์šฐ์‹œ์•ˆ ์ปค๋„ (1.5) ์ ์šฉํ•˜๊ธฐ
cv::Mat gauss = cv::getGaussianKernel(9, 1.5, CV_32F);
๋‹ˆ. void cv::getDerivKernel(cv::OutputArray ky, int dx, int dy, int ksize, bool normalize =false) - x, y์ถ•์œผ๋กœ ๋‚˜๋ˆ  ํ•„ํ„ฐ ๊ณ„์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
ex) //๋ถ„๋ฆฌ๋œ ์ปค๋„๋กœ (2.5) ์ ์šฉํ•˜๊ธฐ
cv::Mat kx, ky;
cv::getDerivKernels(kx, ky, 2, 2, 7, true);
๋””. void cv::medianBlur(cv::InputArray src, cv::OutputArray dst, int ksize) - ๋ฏธ๋””์•ˆ ๋ธ”๋Ÿฌ(์ค‘๊ฐ„๊ฐ’ ) ์ ์šฉ ํ•จ์ˆ˜
ex) //๋ฏธ๋””์•ˆ ๋ธ”๋Ÿฌ ํ•„ํ„ฐ ์ ์šฉ
cv::medianBlur(image, result, 5);
๋ฆฌ. void cv::resize(cv::InputArray src, cv::OutputArray dst, cv::Size dsize, double fx = (0,0), double fy = (0,0), int interpolation = 1) - ์žฌ์ƒ˜ํ”Œ๋ง ํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์˜์ƒ์˜ ํฌ๊ธฐ๋ฅผ ์กฐ์ •ํ•  ๋•Œ(์ถ•์†Œ, ํ™•๋Œ€) ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋‹ค. ๋งˆ์ง€๋ง‰ ์ธ์ˆ˜๋Š” ๋ณด๊ฐ„๋ฐฉ์‹์„ ์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
ex) cv::resize(reduced, reduced, cv::Size(), 4, 4, cv::INTER_NEAREST);
๋ฏธ. void cv::pyrDown / cv::pyrUp(cv::InputArray src, cv::OutputArray dst, const cv::Szie &dstsize = cv::Size(), int borderType =4) - ์‚ฌ์ด์ฆˆ๋ฅผ 2๋ฐฐ๋กœ ์ถ•์†Œ/ํ™•๋Œ€ ํ•˜๋Š” ํ•จ์ˆ˜. ํ”ผ๋ผ๋ฏธ๋“œ ์˜์ƒ ์ œ์ž‘์‹œ์— ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.
ex) cv::pyrDown(image, reduced); //์˜์ƒ์„ ์ ˆ๋ฐ˜์œผ๋กœ ์ถ•์†Œํ•จ
๋น„. void cv::Sobel(cv::InputArray src, cv::OutputArray dst, int ddepth, int dx, int dy, int ksize = 3, double scale = (1.0), double delta = (0.0)) - ์—์ง€๋ฅผ ๊ฒ€์ถœํ•˜๊ธฐ ์œ„ํ•œ ํ•„ํ„ฐ์ด๋‹ค. ๋ฐฉํ–ฅ์„ฑ ํ•„ํ„ฐ๋ผ๊ณ ๋„ ํ•œ๋‹ค.
์‹œ. void cv::Laplacian(cv::InputArray src, cv::OutputArray dst, int ddepth, int ksize =1, double scale = (1.0)) - ๋ผํ”Œ๋ผ์‹œ์•ˆ ๊ณ„์‚ฐํ•˜๋Š” ํ•จ์ˆ˜, ๋ฏธ๋ฐ˜ ๊ณ„์‚ฐ์— ๊ธฐ๋ฐ˜์„ ๋‘๋Š” ๋‹ค๋ฅธ ๊ณ ์ฃผํŒŒ ์„ ํ˜• ํ•„ํ„ฐ๋‹ค. ๊ณก๋ฅ ์„ ์ธก์ •ํ•˜๊ธฐ ์œ„ํ•ด 2์ฐจ ๋ฏธ๋ถ„์„ ๊ณ„์‚ฐํ•œ๋‹ค.
์ด. void cv::minMaxLoc(cv::InputArray src, double *minVal, doulbe *maxVal = (double *)0, cv::Point *minLoc = (cv::Point *)0, *maxLoc = (cv::Point *)0, mask) - ๋ฐฐ์—ด์—์„œ์˜ ์ตœ์†Ÿ๊ฐ’๊ณผ ์ตœ๋Œ€๊ฐ’์„ ์ฐพ์•„ ๋„ฃ๋Š”๋‹ค.
์ง€.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment