diff --git a/CMakeLists.txt b/CMakeLists.txt index 03e8d1afd6..75fcf9659b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -473,14 +473,22 @@ include(cmake/OpenCVFindLibsPerf.cmake) # Detect other 3rd-party libraries/tools # ---------------------------------------------------------------------------- -# --- LATEX for pdf documentation --- -unset(HAVE_DOXYGEN CACHE) +# --- Doxygen and PlantUML for documentation --- +unset(DOXYGEN_FOUND CACHE) if(BUILD_DOCS) - include(cmake/OpenCVFindLATEX.cmake) - find_host_program(DOXYGEN_BUILD doxygen) - if (DOXYGEN_BUILD) - set(HAVE_DOXYGEN 1) - endif (DOXYGEN_BUILD) + find_package(Doxygen) + if (PLANTUML_JAR) + message(STATUS "Using PlantUML path from command line: ${PLANTUML_JAR}") + elseif(DEFINED ENV{PLANTUML_JAR}) + set(PLANTUML_JAR $ENV{PLANTUML_JAR}) + message(STATUS "Using PLantUML path from environment: ${PLANTUML_JAR}") + else() + message(STATUS "To enable PlantUML support, set PLANTUML_JAR environment variable or pass -DPLANTUML_JAR= option to cmake") + endif() + if (PLANTUML_JAR AND DOXYGEN_VERSION VERSION_LESS 1.8.8) + message(STATUS "You need Doxygen version 1.8.8 or later to use PlantUML") + unset(PLANTUML_JAR) + endif() endif(BUILD_DOCS) # --- Python Support --- @@ -1083,15 +1091,8 @@ endif() if(BUILD_DOCS) status("") status(" Documentation:") - if(HAVE_SPHINX) - status(" Build Documentation:" PDFLATEX_COMPILER THEN YES ELSE "YES (only HTML and without math expressions)") - else() - status(" Build Documentation:" NO) - endif() - status(" Sphinx:" HAVE_SPHINX THEN "${SPHINX_BUILD} (ver ${SPHINX_VERSION})" ELSE NO) - status(" PdfLaTeX compiler:" PDFLATEX_COMPILER THEN "${PDFLATEX_COMPILER}" ELSE NO) - status(" PlantUML:" PLANTUML THEN "${PLANTUML}" ELSE NO) - status(" Doxygen:" HAVE_DOXYGEN THEN "YES (${DOXYGEN_BUILD})" ELSE NO) + status(" Doxygen:" DOXYGEN_FOUND THEN "${DOXYGEN_EXECUTABLE} (ver ${DOXYGEN_VERSION})" ELSE NO) + status(" PlantUML:" PLANTUML_JAR THEN "${PLANTUML_JAR}" ELSE NO) endif() # ========================== samples and tests ========================== diff --git a/cmake/OpenCVDetectPython.cmake b/cmake/OpenCVDetectPython.cmake index a19fd9f70f..eb2c7bccbf 100644 --- a/cmake/OpenCVDetectPython.cmake +++ b/cmake/OpenCVDetectPython.cmake @@ -237,21 +237,3 @@ if(PYTHON2INTERP_FOUND) set(PYTHON_DEFAULT_AVAILABLE "TRUE") set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON2_EXECUTABLE}") endif() - -unset(HAVE_SPHINX CACHE) - -if(BUILD_DOCS) - find_host_program(SPHINX_BUILD sphinx-build) - find_host_program(PLANTUML plantuml) - if(SPHINX_BUILD) - execute_process(COMMAND "${SPHINX_BUILD}" - OUTPUT_QUIET - ERROR_VARIABLE SPHINX_OUTPUT - OUTPUT_STRIP_TRAILING_WHITESPACE) - if(SPHINX_OUTPUT MATCHES "Sphinx v([0-9][^ \n]*)") - set(SPHINX_VERSION "${CMAKE_MATCH_1}") - set(HAVE_SPHINX 1) - message(STATUS "Found Sphinx ${SPHINX_VERSION}: ${SPHINX_BUILD}") - endif() - endif() -endif(BUILD_DOCS) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index cc54e7414d..cb0d40d949 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -2,7 +2,7 @@ # CMake file for OpenCV docs #----------------------- -set(HAVE_DOC_GENERATOR BUILD_DOCS AND (HAVE_SPHINX OR HAVE_DOXYGEN)) +set(HAVE_DOC_GENERATOR BUILD_DOCS AND DOXYGEN_FOUND) if(HAVE_DOC_GENERATOR) project(opencv_docs) @@ -34,120 +34,9 @@ if(HAVE_DOC_GENERATOR) set(OPTIONAL_DOC_LIST "") endif(HAVE_DOC_GENERATOR) -# ========= Sphinx docs ========= -if(BUILD_DOCS AND HAVE_SPHINX) - if(NOT INSTALL_CREATE_DISTRIB) - list(APPEND DOC_LIST "${OpenCV_SOURCE_DIR}/doc/haartraining.htm") - endif() - - # build lists of documentation files and generate table of contents for reference manual - set(DOC_FAKE_ROOT "${CMAKE_CURRENT_BINARY_DIR}/fake-root") - set(DOC_FAKE_ROOT_FILES "") - - function(ocv_doc_add_file_to_fake_root source destination) - add_custom_command( - OUTPUT "${DOC_FAKE_ROOT}/${destination}" - COMMAND "${CMAKE_COMMAND}" -E copy "${source}" "${DOC_FAKE_ROOT}/${destination}" - DEPENDS "${source}" - COMMENT "Copying ${destination} to fake root..." - VERBATIM - ) - list(APPEND DOC_FAKE_ROOT_FILES "${DOC_FAKE_ROOT}/${destination}") - set(DOC_FAKE_ROOT_FILES "${DOC_FAKE_ROOT_FILES}" PARENT_SCOPE) - endfunction() - - function(ocv_doc_add_to_fake_root source) - if(ARGC GREATER 1) - set(destination "${ARGV1}") - else() - file(RELATIVE_PATH destination "${OpenCV_SOURCE_DIR}" "${source}") - endif() - - if(IS_DIRECTORY "${source}") - file(GLOB_RECURSE files RELATIVE "${source}" "${source}/*") - - foreach(file ${files}) - ocv_doc_add_file_to_fake_root("${source}/${file}" "${destination}/${file}") - endforeach() - else() - ocv_doc_add_file_to_fake_root("${source}" "${destination}") - endif() - - set(DOC_FAKE_ROOT_FILES "${DOC_FAKE_ROOT_FILES}" PARENT_SCOPE) - endfunction() - - set(OPENCV_REFMAN_TOC "") - - foreach(mod ${BASE_MODULES} ${EXTRA_MODULES}) - if(EXISTS "${OPENCV_MODULE_opencv_${mod}_LOCATION}/doc/${mod}.rst") - ocv_doc_add_to_fake_root("${OPENCV_MODULE_opencv_${mod}_LOCATION}/doc" modules/${mod}/doc) - set(OPENCV_REFMAN_TOC "${OPENCV_REFMAN_TOC} ${mod}/doc/${mod}.rst\n") - endif() - endforeach() - - configure_file("${OpenCV_SOURCE_DIR}/modules/refman.rst.in" "${DOC_FAKE_ROOT}/modules/refman.rst" @ONLY) - - ocv_doc_add_to_fake_root("${OpenCV_SOURCE_DIR}/index.rst") - ocv_doc_add_to_fake_root("${OpenCV_SOURCE_DIR}/doc") - ocv_doc_add_to_fake_root("${OpenCV_SOURCE_DIR}/platforms/android") - ocv_doc_add_to_fake_root("${OpenCV_SOURCE_DIR}/samples") - - set(BUILD_PLANTUML "") - if(PLANTUML) - set(BUILD_PLANTUML "-tplantuml") - endif() - - if(PDFLATEX_COMPILER) - add_custom_target(docs - COMMAND ${SPHINX_BUILD} ${BUILD_PLANTUML} -b latex -c "${CMAKE_CURRENT_SOURCE_DIR}" "${DOC_FAKE_ROOT}" . - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/mymath.sty ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/patch_refman_latex.py" opencv2refman.tex - COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/patch_refman_latex.py" opencv2manager.tex - COMMAND ${CMAKE_COMMAND} -E echo "Generating opencv2refman.pdf" - COMMAND ${PDFLATEX_COMPILER} -interaction=batchmode opencv2refman.tex - COMMAND ${PDFLATEX_COMPILER} -interaction=batchmode opencv2refman.tex - COMMAND ${CMAKE_COMMAND} -E echo "Generating opencv2manager.pdf" - COMMAND ${PDFLATEX_COMPILER} -interaction=batchmode opencv2manager.tex - COMMAND ${PDFLATEX_COMPILER} -interaction=batchmode opencv2manager.tex - COMMAND ${CMAKE_COMMAND} -E echo "Generating opencv_user.pdf" - COMMAND ${PDFLATEX_COMPILER} -interaction=batchmode opencv_user.tex - COMMAND ${PDFLATEX_COMPILER} -interaction=batchmode opencv_user.tex - COMMAND ${CMAKE_COMMAND} -E echo "Generating opencv_tutorials.pdf" - COMMAND ${PDFLATEX_COMPILER} -interaction=batchmode opencv_tutorials.tex - COMMAND ${PDFLATEX_COMPILER} -interaction=batchmode opencv_tutorials.tex - COMMAND ${CMAKE_COMMAND} -E echo "Generating opencv_cheatsheet.pdf" - COMMAND ${PDFLATEX_COMPILER} -interaction=batchmode "${CMAKE_CURRENT_SOURCE_DIR}/opencv_cheatsheet.tex" - COMMAND ${PDFLATEX_COMPILER} -interaction=batchmode "${CMAKE_CURRENT_SOURCE_DIR}/opencv_cheatsheet.tex" - DEPENDS ${DOC_FAKE_ROOT_FILES} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating the PDF Manuals" - ) - - LIST(APPEND OPTIONAL_DOC_LIST "${CMAKE_BINARY_DIR}/doc/opencv2refman.pdf" "${CMAKE_BINARY_DIR}/doc/opencv2manager.pdf" - "${CMAKE_BINARY_DIR}/doc/opencv_user.pdf" "${CMAKE_BINARY_DIR}/doc/opencv_tutorials.pdf" "${CMAKE_BINARY_DIR}/doc/opencv_cheatsheet.pdf") - - if(ENABLE_SOLUTION_FOLDERS) - set_target_properties(docs PROPERTIES FOLDER "documentation") - endif() - endif() - - add_custom_target(html_docs - COMMAND "${SPHINX_BUILD}" ${BUILD_PLANTUML} -b html -c "${CMAKE_CURRENT_SOURCE_DIR}" "${DOC_FAKE_ROOT}" ./_html - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/mymath.sty ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${DOC_FAKE_ROOT_FILES} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating Online Documentation" - ) - - if(ENABLE_SOLUTION_FOLDERS) - set_target_properties(html_docs PROPERTIES FOLDER "documentation") - endif() - -endif() - # ========= Doxygen docs ========= -if(BUILD_DOCS AND HAVE_DOXYGEN) +if(BUILD_DOCS AND DOXYGEN_FOUND) # not documented modules list list(APPEND blacklist "ts" "java" "python2" "python3" "world") @@ -240,19 +129,31 @@ if(BUILD_DOCS AND HAVE_DOXYGEN) set(CMAKE_DOXYGEN_MAIN_REFERENCE "${refs_main}") set(CMAKE_DOXYGEN_EXTRA_REFERENCE "${refs_extra}") set(CMAKE_EXTRA_BIB_FILES "${bibfile} ${paths_bib}") + if (CMAKE_DOXYGEN_GENERATE_QHP) + set(CMAKE_DOXYGEN_GENERATE_QHP "YES") + else() + set(CMAKE_DOXYGEN_GENERATE_QHP "NO") + endif() + + list(APPEND CMAKE_DOXYGEN_HTML_FILES "${CMAKE_CURRENT_SOURCE_DIR}/opencv.ico") + list(APPEND CMAKE_DOXYGEN_HTML_FILES "${CMAKE_CURRENT_SOURCE_DIR}/pattern.png") + list(APPEND CMAKE_DOXYGEN_HTML_FILES "${CMAKE_CURRENT_SOURCE_DIR}/acircles_pattern.png") + list(APPEND CMAKE_DOXYGEN_HTML_FILES "${CMAKE_CURRENT_SOURCE_DIR}/bodybg.png") + list(APPEND CMAKE_DOXYGEN_HTML_FILES "${CMAKE_CURRENT_SOURCE_DIR}/mymath.sty") + string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_HTML_FILES "${CMAKE_DOXYGEN_HTML_FILES}") + + if(PLANTUML_JAR) + set(CMAKE_DOXYGEN_PLANTUML_SUPPORT "PLANTUML_JAR_PATH = ${PLANTUML_JAR}\n") + else() + set(CMAKE_DOXYGEN_PLANTUML_SUPPORT "ALIASES += startuml{1}=\"@warning __No plantuml!__ \\n \\n @if DUMMY_PLANTUML_CODE\" enduml=\"@endif\"\n") + endif() # writing file configure_file(Doxyfile.in ${doxyfile} @ONLY) configure_file(root.markdown.in ${rootfile} @ONLY) - configure_file(mymath.sty "${CMAKE_DOXYGEN_OUTPUT_PATH}/html/mymath.sty" @ONLY) - configure_file(mymath.sty "${CMAKE_DOXYGEN_OUTPUT_PATH}/latex/mymath.sty" @ONLY) - # TODO: do not store downloadable samples, but give github link instead add_custom_target(doxygen - COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/samples" "${CMAKE_DOXYGEN_OUTPUT_PATH}/html/samples" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/pattern.png" "${CMAKE_DOXYGEN_OUTPUT_PATH}/html" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/acircles_pattern.png" "${CMAKE_DOXYGEN_OUTPUT_PATH}/html" - COMMAND ${DOXYGEN_BUILD} ${doxyfile} + COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile} DEPENDS ${doxyfile} ${rootfile} ${bibfile} ${deps} ) endif() @@ -265,4 +166,8 @@ if(HAVE_DOC_GENERATOR) foreach(f ${OPTIONAL_DOC_LIST}) install(FILES "${f}" DESTINATION "${OPENCV_DOC_INSTALL_PATH}" OPTIONAL COMPONENT docs) endforeach() + + # dummy targets + add_custom_target(docs) + add_custom_target(html_docs) endif(HAVE_DOC_GENERATOR) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 624e83bae9..8b310a2e39 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -125,11 +125,11 @@ IGNORE_PREFIX = GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html -HTML_HEADER = -HTML_FOOTER = +HTML_HEADER = @CMAKE_CURRENT_SOURCE_DIR@/header.html +HTML_FOOTER = @CMAKE_CURRENT_SOURCE_DIR@/footer.html HTML_STYLESHEET = -HTML_EXTRA_STYLESHEET = -HTML_EXTRA_FILES = +HTML_EXTRA_STYLESHEET = @CMAKE_CURRENT_SOURCE_DIR@/stylesheet.css +HTML_EXTRA_FILES = @CMAKE_DOXYGEN_HTML_FILES@ HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 @@ -148,10 +148,10 @@ GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO -GENERATE_QHP = NO -QCH_FILE = -QHP_NAMESPACE = org.doxygen.Project -QHP_VIRTUAL_FOLDER = doc +GENERATE_QHP = @CMAKE_DOXYGEN_GENERATE_QHP@ +QCH_FILE = ../opencv-@OPENCV_VERSION@.qch +QHP_NAMESPACE = org.itseez.opencv.@OPENCV_VERSION@ +QHP_VIRTUAL_FOLDER = opencv QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = @@ -285,3 +285,4 @@ DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES +@CMAKE_DOXYGEN_PLANTUML_SUPPORT@ diff --git a/doc/_static/insertIframe.js b/doc/_static/insertIframe.js deleted file mode 100644 index 0a3099a8c2..0000000000 --- a/doc/_static/insertIframe.js +++ /dev/null @@ -1,12 +0,0 @@ -function insertIframe (elementId, iframeSrc) -{ - var iframe; - if (document.createElement && (iframe = document.createElement('iframe'))) - { - iframe.src = unescape(iframeSrc); - iframe.width = "100%"; - iframe.height = "511px"; - var element = document.getElementById(elementId); - element.parentNode.replaceChild(iframe, element); - } -} diff --git a/doc/_themes/blue/layout.html b/doc/_themes/blue/layout.html deleted file mode 100644 index d0d43031c8..0000000000 --- a/doc/_themes/blue/layout.html +++ /dev/null @@ -1,227 +0,0 @@ -{# - basic/layout.html - ~~~~~~~~~~~~~~~~~ - - Master layout template for Sphinx themes. - - :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -#} -{%- block doctype -%} - -{%- endblock %} -{% set script_files = script_files + [pathto("_static/insertIframe.js", 1)] %} -{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} -{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} -{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and - (sidebars != []) %} -{%- set url_root = pathto('', 1) %} -{%- if url_root == '#' %}{% set url_root = '' %}{% endif %} - -{%- macro relbar() %} - -{%- endmacro %} - -{%- macro sidebar() %} - {%- if render_sidebar %} -
-
- {%- block sidebarlogo %} - {%- if logo %} - - {%- endif %} - {%- endblock %} - {%- if sidebars == None %} - {%- block sidebarsearch %} - {%- include "searchbox.html" %} - {%- endblock %} - {%- endif %} - {%- if sidebars != None %} - {#- new style sidebar: explicitly include/exclude templates #} - {%- for sidebartemplate in sidebars %} - {%- include sidebartemplate %} - {%- endfor %} - {%- else %} - {#- old style sidebars: using blocks -- should be deprecated #} - {%- block sidebartoc %} - {%- include "localtoc.html" %} - {%- endblock %} - {%- block sidebarrel %} - {%- include "relations.html" %} - {%- endblock %} - {%- block sidebarsourcelink %} - {%- include "sourcelink.html" %} - {%- endblock %} - {%- if customsidebar %} - {%- include customsidebar %} - {%- endif %} - {%- endif %} -
-
- {%- endif %} -{%- endmacro %} - - - - - {{ metatags }} - {%- if not embedded and docstitle %} - {%- set titlesuffix = " — "|safe + docstitle|e %} - {%- else %} - {%- set titlesuffix = "" %} - {%- endif %} - {%- block htmltitle %} - {{ title|striptags|e }}{{ titlesuffix }} - {%- endblock %} - - - {%- for cssfile in css_files %} - - {%- endfor %} - {%- if not embedded %} - - {%- for scriptfile in script_files %} - - {%- endfor %} - {%- if use_opensearch %} - - {%- endif %} - {%- if favicon %} - - {%- endif %} - {%- endif %} -{%- block linktags %} - {%- if hasdoc('about') %} - - {%- endif %} - {%- if hasdoc('genindex') %} - - {%- endif %} - {%- if hasdoc('search') %} - - {%- endif %} - {%- if hasdoc('copyright') %} - - {%- endif %} - - {%- if parents %} - - {%- endif %} - {%- if next %} - - {%- endif %} - {%- if prev %} - - {%- endif %} -{%- endblock %} -{%- block extrahead %} {% endblock %} - - -{%- block header %}{% endblock %} - -{%- block relbar1 %}{{ relbar() }}{% endblock %} - -{%- block content %} - {%- block sidebar1 %} {# possible location for sidebar #} {% endblock %} - -
- {% block document %} -
- {%- if not embedded %}{% if not theme_nosidebar|tobool %} -
- {%- endif %}{% endif %} -
- {% block body %} {% endblock %} -
- - {%- if not embedded %}{% if not theme_nosidebar|tobool %} -
- {%- endif %}{% endif %} -
-{% endblock %} - - {%- block sidebar2 %}{{ sidebar() }}{% endblock %} -
-
-{%- endblock %} - -{%- block relbar2 %}{{ relbar() }}{% endblock %} - -{%- block footer %} - -{%- endblock %} - - diff --git a/doc/_themes/blue/searchbox.html b/doc/_themes/blue/searchbox.html deleted file mode 100644 index d5b45a793e..0000000000 --- a/doc/_themes/blue/searchbox.html +++ /dev/null @@ -1,21 +0,0 @@ -{# - basic/searchbox.html - ~~~~~~~~~~~~~~~~~~~~ - - Sphinx sidebar template: quick search box. - - :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -#} -{%- if pagename != "search" %} - - -{%- endif %} diff --git a/doc/_themes/blue/static/default.css_t b/doc/_themes/blue/static/default.css_t deleted file mode 100644 index 4d410be8aa..0000000000 --- a/doc/_themes/blue/static/default.css_t +++ /dev/null @@ -1,390 +0,0 @@ -/** - * Sphinx stylesheet -- default theme - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: {{ theme_bodyfont }}; - font-size: 100%; - background-color: {{ theme_footerbgcolor }}; - color: #000; - margin: 0; - padding: 0; -} - -img.logo { - width: 150px; -} - -div.document { - background-color: {{ theme_sidebarbgcolor }}; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 270px; -} - -div.body { - background-color: {{ theme_bgcolor }}; - color: {{ theme_textcolor }}; - padding: 0 20px 30px 20px; -} - -div.feedback { - background-color: {{ theme_feedbackbgcolor }}; - color: {{ theme_feedbacktextcolor }}; - padding: 20px 20px 30px 20px; -} - -div.feedback h2 { - margin: 10px 0 10px 0; -} - -div.feedback a { - color: {{ theme_feedbacklinkcolor }}; - font-weight: bold; -} - -{%- if theme_rightsidebar|tobool %} -div.bodywrapper { - margin: 0 230px 0 0; -} -{%- endif %} - -div.footer { - color: {{ theme_footertextcolor }}; - width: 100%; - padding: 9px 0 9px 0; - text-align: center; - font-size: 75%; -} - -div.footer a { - color: {{ theme_footertextcolor }}; - text-decoration: underline; -} - -div.related { - background-color: {{ theme_relbarbgcolor }}; - line-height: 30px; - color: {{ theme_relbartextcolor }}; -} - -div.related a { - color: {{ theme_relbarlinkcolor }}; -} - -div.sphinxsidebar { - word-wrap: break-word; - width: 270px; - {%- if theme_stickysidebar|tobool %} - top: 30px; - margin: 0; - position: fixed; - overflow: auto; - height: 100%; - {%- endif %} - {%- if theme_rightsidebar|tobool %} - float: right; - {%- if theme_stickysidebar|tobool %} - right: 0; - {%- endif %} - {%- endif %} -} - -{%- if theme_stickysidebar|tobool %} -/* this is nice, but it it leads to hidden headings when jumping - to an anchor */ -/* -div.related { - position: fixed; -} - -div.documentwrapper { - margin-top: 30px; -} -*/ -{%- endif %} - -div.sphinxsidebar h3 { - font-family: {{ theme_headfont }}; - color: {{ theme_sidebartextcolor }}; - font-size: 1.4em; - font-weight: normal; - margin: 0; - padding: 0; -} - -div.sphinxsidebar h3 a { - color: {{ theme_sidebartextcolor }}; -} - -div.sphinxsidebar h4 { - font-family: {{ theme_headfont }}; - color: {{ theme_sidebartextcolor }}; - font-size: 1.3em; - font-weight: normal; - margin: 5px 0 0 0; - padding: 0; -} - -div.sphinxsidebar p { - color: {{ theme_sidebartextcolor }}; -} - -div.sphinxsidebar p.topless { - margin: 5px 10px 10px 10px; -} - -div.sphinxsidebar ul { - margin: 10px 0 10px 10px; - padding: 0; - color: {{ theme_sidebartextcolor }}; -} - -div.sphinxsidebar a { - color: {{ theme_sidebarlinkcolor }}; -} - -div.sphinxsidebar input { - border: 1px solid {{ theme_sidebarlinkcolor }}; - font-family: sans-serif; - font-size: 1em; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: {{ theme_linkcolor }}; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -div.body p, div.body dd, div.body li { - text-align: justify; - line-height: 130%; - margin-top: 1em; - margin-bottom: 1em; -} - -div.toctree-wrapper li, ul.simple li { - margin:0; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: {{ theme_headfont }}; - background-color: {{ theme_headbgcolor }}; - font-weight: normal; - color: {{ theme_headtextcolor }}; - border-bottom: 1px solid #ccc; - margin: 20px -20px 10px -20px; - padding: 3px 0 3px 10px; -} - -a.toc-backref, a.toc-backref:hover { - font-family: {{ theme_headfont }}; - background-color: {{ theme_headbgcolor }}; - font-weight: normal; - color: {{ theme_headtextcolor }}; - text-decoration: none; -} - -div.body h1 { margin-top: 0; font-size: 200%; } -div.body h2 { font-size: 160%; } -div.body h3 { font-size: 140%; } -div.body h4 { font-size: 120%; } -div.body h5 { font-size: 110%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: {{ theme_headlinkcolor }}; - font-size: 0.8em; - padding: 0 4px 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - background-color: {{ theme_headlinkcolor }}; - color: white; -} - - -div.body p, div.body dd, div.body li { - text-align: justify; - line-height: 130%; -} - -div.admonition p.admonition-title + p { - display: inline; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre { - padding: 5px; - background-color: {{ theme_codebgcolor }}; - color: {{ theme_codetextcolor }}; - line-height: 120%; - border: 1px solid #ace; - border-left: none; - border-right: none; -} - -tt { - color: {{ theme_headtextcolor }}; - /*background-color: #ecf0f3;*/ - padding: 0 1px 0 1px; - font-size: 1.2em; -} - -tt.descname { - color: {{ theme_headtextcolor }}; - /*background-color: #ecf0f3;*/ - padding: 0 1px 0 1px; - font-size: 1.4em; -} - -div.math p { - margin-top: 10px; - margin-bottom: 10px; -} - -dl.function > dt:first-child { - margin-bottom: 7px; -} - -dl.cfunction > dt:first-child { - margin-bottom: 7px; - color: #8080B0; -} - -dl.cfunction > dt:first-child tt.descname -{ - color: #8080B0; -} - - -dl.pyfunction > dt:first-child { - margin-bottom: 7px; -} - -dl.jfunction > dt:first-child { - margin-bottom: 7px; -} - -table.field-list { - margin-top: 20px; -} - -/*ul.simple { - list-style: none; -}*/ - -em.menuselection, em.guilabel { - font-family: {{ theme_guifont }}; -} - -.enumeratevisibleitemswithsquare ul { -list-style: square; -margin-bottom: 0px; -margin-left: 0px; -margin-right: 0px; -margin-top: 0px; -} - -.enumeratevisibleitemswithsquare li { -margin-bottom: 0.2em; -margin-left: 0px; -margin-right: 0px; -margin-top: 0.2em; - } - - .enumeratevisibleitemswithsquare p { - margin-bottom: 0pt; - margin-top: 1pt; - } - - .enumeratevisibleitemswithsquare dl{ -margin-bottom: 0px; -margin-left: 0px; -margin-right: 0px; -margin-top: 0px; - } - - .toctableopencv - { - width: 100% ; - table-layout: fixed; - } - - - .toctableopencv colgroup col:first-child - { - width: 100pt !important; - max-width: 100pt !important; - min-width: 100pt !important; - } - - .toctableopencv colgroup col:nth-child(2) - { - width: 100% !important; - } - -div.body ul.search li { - text-align: left; -} - -div.linenodiv { - min-width: 1em; - text-align: right; -} - -div.sphinxsidebar #searchbox input[type="text"] { - width:auto; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - width:auto; -} diff --git a/doc/_themes/blue/theme.conf b/doc/_themes/blue/theme.conf deleted file mode 100644 index bc0b99b2a3..0000000000 --- a/doc/_themes/blue/theme.conf +++ /dev/null @@ -1,31 +0,0 @@ -[theme] -inherit = basic -stylesheet = default.css -pygments_style = sphinx - -[options] -rightsidebar = false -stickysidebar = false -footerbgcolor = #004068 -footertextcolor = #ffffff -sidebarbgcolor = #006090 -sidebartextcolor = #ffffff -sidebarlinkcolor = #cceeff -relbarbgcolor = #003048 -relbartextcolor = #ffffff -relbarlinkcolor = #ffffff -bgcolor = #ffffff -textcolor = #000000 -headbgcolor = #f2f2f2 -headtextcolor = #003048 -headlinkcolor = #65a136 -linkcolor = #0090d9 -codebgcolor = #e0f5ff -codetextcolor = #333333 -feedbackbgcolor = #004068 -feedbacktextcolor = #ffffff -feedbacklinkcolor = #ffffff -bodyfont = sans-serif -headfont = 'Trebuchet MS', sans-serif -guifont = "Lucida Sans","Lucida Sans Unicode","Lucida Grande",Verdana,Arial,Helvetica,sans-serif -lang = none diff --git a/doc/_themes/sphinxdoc/layout.html b/doc/_themes/sphinxdoc/layout.html deleted file mode 100644 index 1064527679..0000000000 --- a/doc/_themes/sphinxdoc/layout.html +++ /dev/null @@ -1,274 +0,0 @@ -{# - basic/layout.html - ~~~~~~~~~~~~~~~~~ - - Master layout template for Sphinx themes. - - :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -#} -{%- block doctype -%} - -{%- endblock %} -{% set script_files = script_files + [pathto("_static/insertIframe.js", 1)] %} -{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} -{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} -{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and - (sidebars != []) %} -{%- set url_root = pathto('', 1) %} -{# XXX necessary? #} -{%- if url_root == '#' %}{% set url_root = '' %}{% endif %} -{%- if not embedded and docstitle %} - {%- set titlesuffix = " — "|safe + docstitle|e %} -{%- else %} - {%- set titlesuffix = "" %} -{%- endif %} - -{%- macro relbar() %} - -{%- endmacro %} - -{%- macro sidebar() %} - {%- if render_sidebar %} -
-
- {%- block sidebarlogo %} - {%- if logo %} - - {%- endif %} - {%- endblock %} - {%- if sidebars == None %} - {%- block sidebarsearch %} - {%- include "searchbox.html" %} - {%- endblock %} - {%- endif %} - {%- if sidebars != None %} - {#- new style sidebar: explicitly include/exclude templates #} - {%- for sidebartemplate in sidebars %} - {%- include sidebartemplate %} - {%- endfor %} - {%- else %} - {#- old style sidebars: using blocks -- should be deprecated #} - {%- block sidebartoc %} - {%- include "localtoc.html" %} - {%- endblock %} - {%- block sidebarrel %} - {%- include "relations.html" %} - {%- endblock %} - {%- if customsidebar %} - {%- include customsidebar %} - {%- endif %} - {%- endif %} -
-
- {%- endif %} -{%- endmacro %} - -{%- macro script() %} - - {%- for scriptfile in script_files %} - - {%- endfor %} -{%- endmacro %} - -{%- macro css() %} - - - {%- for cssfile in css_files %} - - {%- endfor %} -{%- endmacro %} - - - - - {{ metatags }} - {%- block htmltitle %} - {{ title|striptags|e }}{{ titlesuffix }} - {%- endblock %} - {{ css() }} - {%- if not embedded %} - {{ script() }} - {%- if use_opensearch %} - - {%- endif %} - {%- if favicon %} - - {%- endif %} - {%- endif %} -{%- block linktags %} - {%- if hasdoc('about') %} - - {%- endif %} - {%- if hasdoc('genindex') %} - - {%- endif %} - {%- if hasdoc('search') %} - - {%- endif %} - {%- if hasdoc('copyright') %} - - {%- endif %} - - {%- if parents %} - - {%- endif %} - {%- if next %} - - {%- endif %} - {%- if prev %} - - {%- endif %} -{%- endblock %} -{%- block extrahead %} - -{%- if not embedded %} - - -{%- endif %} -{% endblock %} - -{%- block header %}{% endblock %} - -{%- block relbar1 %}{{ relbar() }}{% endblock %} - - {%- block sidebar1 %} {# possible location for sidebar #} {% endblock %} - {%- block sidebar2 %}{{ sidebar() }}{% endblock %} - - -{%- block content %} - -
- {%- block document %} -
- {%- if render_sidebar %} -
- {%- endif %} -
- {% block body %} {% endblock %} -
- - {%- if render_sidebar %} -
- {%- endif %} -
- {%- endblock %} - -
-
-{%- endblock %} - -{%- block relbar2 %}{{ relbar() }}{% endblock %} - -{%- block footer %} - -{%- endblock %} - - diff --git a/doc/_themes/sphinxdoc/searchbox.html b/doc/_themes/sphinxdoc/searchbox.html deleted file mode 100644 index 73616d9ed4..0000000000 --- a/doc/_themes/sphinxdoc/searchbox.html +++ /dev/null @@ -1,21 +0,0 @@ -{# - basic/searchbox.html - ~~~~~~~~~~~~~~~~~~~~ - - Sphinx sidebar template: quick search box. - - :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -#} -{%- if pagename != "search" and builder != "singlehtml" %} - - -{%- endif %} diff --git a/doc/_themes/sphinxdoc/static/default.css_t b/doc/_themes/sphinxdoc/static/default.css_t deleted file mode 100644 index ce5ee06350..0000000000 --- a/doc/_themes/sphinxdoc/static/default.css_t +++ /dev/null @@ -1,466 +0,0 @@ -/* - * sphinxdoc.css_t - * ~~~~~~~~~~~~~~~ - * - * Sphinx stylesheet -- sphinxdoc theme. - * - * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; - font-size: 14px; - text-align: center; - background-image: url(bodybg.png); - color: black; - padding: 0; - border-right: 1px solid #0a507a; - border-left: 1px solid #0a507a; - - margin: 0 auto; - min-width: 780px; - max-width: 1080px; -} - -div.document { - background-color: white; - text-align: left; -} - -div.bodywrapper { - margin: 0 240px 0 0; - border-right: 1px solid #0a507a; -} - -div.body { - margin: 0; - padding: 0.5em 20px 20px 20px; -} - -div.related { - font-size: 1em; - color: white; -} - -div.related ul { - background-image: url(relbg.png); - text-align: left; - border-top: 1px solid #002e50; - border-bottom: 1px solid #002e50; -} - -div.related li + li { - display: inline; -} - -div.related ul li.right { - float: right; - margin-right: 5px; -} - -div.related ul li a { - margin: 0; - padding: 0 5px 0 5px; - line-height: 1.75em; - color: #f9f9f0; - text-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5); -} - -div.related ul li a:hover { - color: white; - text-shadow: 0px 0px 1px rgba(255, 255, 255, 0.5); -} - -div.footer { - background-image: url(footerbg.png); - color: #ccc; - text-shadow: 0 0 .2px rgba(255, 255, 255, 0.8); - padding: 3px 8px 3px 0; - clear: both; - font-size: 0.8em; - text-align: center; -} - -div.sphinxsidebarwrapper { - position: relative; - top: 0px; - padding: 0; -} - -div.sphinxsidebar { - word-wrap: break-word; - margin: 0; - padding: 0 15px 15px 0; - width: 210px; - float: right; - font-size: 1em; - text-align: left; -} - -div.sphinxsidebar .logo { - text-align: center; -} - -div.sphinxsidebar .logo img { - width: 150px; - vertical-align: middle; -} - -div.sphinxsidebar input { - border: 1px solid #aaa; - font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox input[type="text"] { - width: 160px; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - width: 40px; -} - -div.sphinxsidebar h3 { - font-size: 1.5em; - border-top: 1px solid #0a507a; - margin-top: 1em; - margin-bottom: 0.5em; - padding-top: 0.5em; -} - -div.sphinxsidebar h4 { - font-size: 1.2em; - margin-bottom: 0; -} - -div.sphinxsidebar h3, div.sphinxsidebar h4 { - margin-right: -15px; - margin-left: -15px; - padding-right: 14px; - padding-left: 14px; - color: #333; - font-weight: 300; - /*text-shadow: 0px 0px 0.5px rgba(0, 0, 0, 0.4);*/ -} - -div.sphinxsidebarwrapper > h3:first-child { - margin-top: 0.5em; - border: none; -} - -div.sphinxsidebar h3 a { - color: #333; -} - -div.sphinxsidebar ul { - color: #444; - margin-top: 7px; - padding: 0; - line-height: 130%; -} - -div.sphinxsidebar ul ul { - margin-left: 20px; - list-style-image: url(listitem.png); -} - -/* -- body styles ----------------------------------------------------------- */ - -p { - margin: 0.8em 0 0.5em 0; -} - -a, a tt { - color: #2878a2; -} - -a:hover, a tt:hover { - color: #68b8c2; -} - -a tt { - border: 0; -} - -h1, h2, h3, h4, h5, h6 { - color: #0a507a; - background-color: #e5f5ff; - font-weight: 300; -} - -h1 { - margin: 10px 0 0 0; -} - -h2 { - margin: 1.em 0 0.2em 0; - padding: 0; -} - -h3 { - margin: 1em 0 -0.3em 0; -} - -h1 { font-size: 200%; } -h2 { font-size: 160%; } -h3 { font-size: 140%; } -h4 { font-size: 120%; } -h5 { font-size: 110%; } -h6 { font-size: 100%; } - -div a, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { - text-decoration: none; -} - -div.body h1 a tt, div.body h2 a tt, div.body h3 a tt, -div.body h4 a tt, div.body h5 a tt, div.body h6 a tt { - color: #0a507a !important; - font-size: inherit !important; -} - -a.headerlink { - color: #0a507a !important; - font-size: 12px; - margin-left: 6px; - padding: 0 4px 0 4px; - text-decoration: none !important; - float: right; -} - -a.headerlink:hover { - background-color: #ccc; - color: white!important; -} - -cite, code, tt { - font-family: 'Consolas', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', - monospace; - font-size: 14px; - min-width: 780px; - max-width: 1080px; -} - -tt { - color: #003048; - padding: 1px; -} - -tt.descname, tt.descclassname, tt.xref { - font-size: 12px; -} - -hr { - border: 1px solid #abc; - margin: 2em; -} - -pre { - font-family: 'Consolas', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', - monospace; - font-size: 13px; - letter-spacing: 0.015em; - line-height: 120%; - padding: 0.5em; - border: 1px solid #ccc; - border-radius: 2px; - background-color: #f8f8f8; -} - -pre a { - color: inherit; - text-decoration: none; -} - -td.linenos pre { - padding: 0.5em 0; -} - -td.code pre { - max-width: 740px; - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -div.quotebar { - background-color: #f8f8f8; - max-width: 250px; - float: right; - padding: 0px 7px; - border: 1px solid #ccc; - margin-left: 1em; -} - -div.topic { - background-color: #f8f8f8; -} - -table { - border-collapse: collapse; - margin: 0 -0.5em 0 -0.5em; -} - -table td, table th { - padding: 0.2em 0.5em 0.2em 0.5em; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -div.admonition ul li, div.warning ul li, -div.admonition ol li, div.warning ol li { - text-align: left; -} - -div.admonition p.admonition-title + p { - display: inline; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -/* ------------------ our styles ----------------*/ - -div.body p, div.body dd, div.body li { - text-align: justify; - line-height: 130%; - margin-top: 1em; - margin-bottom: 1em; -} - -div.toctree-wrapper li, ul.simple li { - margin:0; -} - -/*a.toc-backref { -}*/ - -div.feedback { - /*background-color: #;*/ - /*color: #;*/ - padding: 20px 20px 30px 20px; - border-top: 1px solid #002e50; -} - -div.feedback h2 { - margin: 10px 0 10px 0; -} - -div.feedback a { - /*color: #;*/ - font-weight: bold; -} - -div.math p { - margin-top: 10px; - margin-bottom: 10px; -} - -dl.function > dt:first-child { - margin-bottom: 7px; -} - -dl.cfunction > dt:first-child { - margin-bottom: 7px; - color: #8080B0; -} - -dl.cfunction > dt:first-child tt.descname { - color: #8080B0; -} - -dl.pyfunction > dt:first-child { - margin-bottom: 7px; -} - -dl.jfunction > dt:first-child { - margin-bottom: 7px; -} - -table.field-list { - margin-top: 20px; -} - -em.menuselection, em.guilabel { - font-family: 'Lucida Sans', 'Lucida Sans Unicode', 'Lucida Grande', Verdana, - Arial, Helvetica, sans-serif; -} - -.enumeratevisibleitemswithsquare ul { - list-style: square; - margin-bottom: 0px; - margin-left: 0px; - margin-right: 0px; - margin-top: 0px; -} - -.enumeratevisibleitemswithsquare li { - margin-bottom: 0.2em; - margin-left: 0px; - margin-right: 0px; - margin-top: 0.2em; - } - -.enumeratevisibleitemswithsquare p { - margin-bottom: 0pt; - margin-top: 1pt; -} - -.enumeratevisibleitemswithsquare dl { - margin-bottom: 0px; - margin-left: 0px; - margin-right: 0px; - margin-top: 0px; -} - -.toctableopencv { - width: 100% ; - table-layout: fixed; -} - -.toctableopencv colgroup col:first-child { - width: 100pt !important; - max-width: 100pt !important; - min-width: 100pt !important; -} - -.toctableopencv colgroup col:nth-child(2) { - width: 100% !important; -} - -div.body ul.search li { - text-align: left; -} - -div.linenodiv { - min-width: 1em; - text-align: right; -} diff --git a/doc/_themes/sphinxdoc/static/footerbg.png b/doc/_themes/sphinxdoc/static/footerbg.png deleted file mode 100644 index df783e2c76..0000000000 Binary files a/doc/_themes/sphinxdoc/static/footerbg.png and /dev/null differ diff --git a/doc/_themes/sphinxdoc/static/headerbg.png b/doc/_themes/sphinxdoc/static/headerbg.png deleted file mode 100644 index 22830f99ef..0000000000 Binary files a/doc/_themes/sphinxdoc/static/headerbg.png and /dev/null differ diff --git a/doc/_themes/sphinxdoc/static/listitem.png b/doc/_themes/sphinxdoc/static/listitem.png deleted file mode 100644 index e45715f914..0000000000 Binary files a/doc/_themes/sphinxdoc/static/listitem.png and /dev/null differ diff --git a/doc/_themes/sphinxdoc/static/relbg.png b/doc/_themes/sphinxdoc/static/relbg.png deleted file mode 100644 index 2006af7d2a..0000000000 Binary files a/doc/_themes/sphinxdoc/static/relbg.png and /dev/null differ diff --git a/doc/_themes/sphinxdoc/theme.conf b/doc/_themes/sphinxdoc/theme.conf deleted file mode 100644 index 1f5132065d..0000000000 --- a/doc/_themes/sphinxdoc/theme.conf +++ /dev/null @@ -1,4 +0,0 @@ -[theme] -inherit = basic -stylesheet = default.css -pygments_style = sphinx diff --git a/doc/_themes/sphinxdoc/static/bodybg.png b/doc/bodybg.png similarity index 100% rename from doc/_themes/sphinxdoc/static/bodybg.png rename to doc/bodybg.png diff --git a/doc/check_docs.py b/doc/check_docs.py deleted file mode 100755 index 96f62f068d..0000000000 --- a/doc/check_docs.py +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/env python - -import sys, glob - -sys.path.append("../modules/python/src2/") -import hdr_parser as hp - -opencv_hdr_list = [ -"../modules/core/include/opencv2/core.hpp", -"../modules/ml/include/opencv2/ml.hpp", -"../modules/imgproc/include/opencv2/imgproc.hpp", -"../modules/calib3d/include/opencv2/calib3d.hpp", -"../modules/features2d/include/opencv2/features2d.hpp", -"../modules/video/include/opencv2/video/tracking.hpp", -"../modules/video/include/opencv2/video/background_segm.hpp", -"../modules/objdetect/include/opencv2/objdetect.hpp", -"../modules/imgcodecs/include/opencv2/imgcodecs.hpp", -"../modules/videoio/include/opencv2/videoio.hpp", -"../modules/highgui/include/opencv2/highgui.hpp", -] - -opencv_module_list = [ -"core", -"imgproc", -"calib3d", -"features2d", -"video", -"objdetect", -"imgcodecs", -"videoio", -"highgui", -"ml" -] - -class RSTParser(object): - - def __init__(self): - self.read_whitelist() - - # reads the file containing functions and classes that do not need to be documented - def read_whitelist(self): - self.whitelist = {} - try: - wf = open("check_docs_whitelist.txt", "rt") - except IOError: - return - self.parser = hp.CppHeaderParser() - - for l in wf.readlines(): - cpos = l.find("#") - if cpos >= 0: - l = l[:cpos] - l = l.strip() - if not l: - continue - rst_decl = None - if "(" in l: - l = l.replace("cv::", "") - rst_decl = self.parser.parse_func_decl_no_wrap(l) - fname = rst_decl[0] - else: - fname = l.replace("::", ".") - complist = fname.split(".") - prefix = "" - alreadyListed = False - wl = [] - for c in complist: - prefix = (prefix + "." + c).lstrip(".") - wl = self.whitelist.get(prefix, []) - if wl == "*": - break - if wl == "*": - continue - if not rst_decl: - self.whitelist[fname] = "*" - else: - wl.append(rst_decl) - self.whitelist[fname] = wl - wf.close() - - def process_rst(self, docname): - df = open(docname, "rt") - fdecl = "" - balance = 0 - lineno = 0 - - for l in df.readlines(): - lineno += 1 - ll = l.strip() - if balance == 0: - if not ll.startswith(".. c:function::") and \ - not ll.startswith(".. cpp:function::") and \ - not ll.startswith(".. ocv:function::") and \ - not ll.startswith(".. ocv:cfunction::"): - continue - fdecl = ll[ll.find("::") + 3:] - elif balance > 0: - fdecl += ll - balance = fdecl.count("(") - fdecl.count(")") - assert balance >= 0 - if balance > 0: - continue - rst_decl = self.parser.parse_func_decl_no_wrap(fdecl) - fname = rst_decl[0] - hdr_decls = self.fmap.get(fname, []) - if not hdr_decls: - fname = fname.replace("cv.", "") - hdr_decls = self.fmap.get(fname, []) - if not hdr_decls: - print "Documented function %s (%s) in %s:%d is not in the headers" % (fdecl, rst_decl[0].replace(".", "::"), docname, lineno) - continue - decl_idx = 0 - for hd in hdr_decls: - if len(hd[3]) != len(rst_decl[3]): - decl_idx += 1 - continue - idx = 0 - for a in hd[3]: - if a[0] != rst_decl[3][idx][0] and a[0].replace("cv::", "") != rst_decl[3][idx][0]: - break - idx += 1 - if idx == len(hd[3]): - break - decl_idx += 1 - if decl_idx < len(hdr_decls): - self.fmap[fname] = hdr_decls[:decl_idx] + hdr_decls[decl_idx+1:] - continue - print "Documented function %s in %s:%d does not have a match" % (fdecl, docname, lineno) - df.close() - - def decl2str(self, decl): - return "%s %s(%s)" % (decl[1], decl[0], ", ".join([a[0] + " " + a[1] for a in decl[3]])) - - def check_module_docs(self, name): - self.parser = hp.CppHeaderParser() - decls = [] - self.fmap = {} - - for hname in opencv_hdr_list: - if hname.startswith("../modules/" + name): - decls += self.parser.parse(hname, wmode=False) - - for d in decls: - fname = d[0] - if not fname.startswith("struct") and not fname.startswith("class") and not fname.startswith("const"): - dlist = self.fmap.get(fname, []) - dlist.append(d) - self.fmap[fname] = dlist - - self.missing_docfunc_list = [] - - doclist = glob.glob("../modules/" + name + "/doc/*.rst") - for d in doclist: - self.process_rst(d) - - print "\n\n########## The list of undocumented functions: ###########\n\n" - misscount = 0 - fkeys = sorted(self.fmap.keys()) - for f in fkeys: - # skip undocumented destructors - if "~" in f: - continue - decls = self.fmap[f] - fcomps = f.split(".") - prefix = "" - wlist_decls = [] - for c in fcomps: - prefix = (prefix + "." + c).lstrip(".") - wlist_decls = self.whitelist.get(prefix, []) - if wlist_decls == "*": - break - if wlist_decls == "*": - continue - wlist_decls = [self.decl2str(d) for d in wlist_decls] - - for d in decls: - dstr = self.decl2str(d) - # special hack for ML: skip old variants of the methods - if name == "ml" and ("CvMat" in dstr): - continue - if dstr not in wlist_decls: - misscount += 1 - print "%s %s(%s)" % (d[1], d[0].replace(".", "::"), ", ".join([a[0] + " " + a[1] for a in d[3]])) - print "\n\n\nundocumented functions in %s: %d" % (name, misscount) - - -p = RSTParser() -for m in opencv_module_list: - print "\n\n*************************** " + m + " *************************\n" - p.check_module_docs(m) diff --git a/doc/check_docs2.py b/doc/check_docs2.py deleted file mode 100755 index 8397204e21..0000000000 --- a/doc/check_docs2.py +++ /dev/null @@ -1,511 +0,0 @@ -#!/usr/bin/env python - -import os, sys, fnmatch, re - -sys.path.append("../modules/python/src2/") -sys.path.append("../modules/java/generator") - -import hdr_parser as hp -import rst_parser as rp - -rp.show_warnings = False -rp.show_errors = False - -allmodules = rp.allmodules -DOCUMENTED_MARKER = "verified" - -ERROR_001_NOTACLASS = 1 -ERROR_002_NOTASTRUCT = 2 -ERROR_003_INCORRECTBASE = 3 -ERROR_004_MISSEDNAMESPACE = 4 -ERROR_005_MISSINGPYFUNC = 5 -ERROR_006_INVALIDPYOLDDOC = 6 -ERROR_007_INVALIDPYDOC = 7 -ERROR_008_CFUNCISNOTGLOBAL = 8 -ERROR_009_OVERLOADNOTFOUND = 9 -ERROR_010_UNKNOWNCLASS = 10 -ERROR_011_UNKNOWNFUNC = 11 - -do_python_crosscheck = True -errors_disabled = [ERROR_004_MISSEDNAMESPACE] - -doc_signatures_whitelist = [ -# templates -"Matx", "Vec", "SparseMat_", "Scalar_", "Mat_", "Ptr", "Size_", "Point_", "Rect_", "Point3_", -"DataType", "detail::RotationWarperBase", "flann::Index_", "CalonderDescriptorExtractor", -"cuda::PtrStepSz", "cuda::PtrStep", "cuda::PtrElemStep_", -# black boxes -"CvArr", "CvFileStorage", -# other -"InputArray", "OutputArray", -] - -defines = ["cvGraphEdgeIdx", "cvFree", "CV_Assert", "cvSqrt", "cvGetGraphVtx", "cvGraphVtxIdx", -"cvCaptureFromFile", "cvCaptureFromCAM", "cvCalcBackProjectPatch", "cvCalcBackProject", -"cvGetHistValue_1D", "cvGetHistValue_2D", "cvGetHistValue_3D", "cvGetHistValue_nD", -"cvQueryHistValue_1D", "cvQueryHistValue_2D", "cvQueryHistValue_3D", "cvQueryHistValue_nD", -# not a real function but behaves as function -"Mat::size", -# ugly "virtual" functions from ml module -"CvStatModel::train", "CvStatModel::predict", -# TODO: -"cvExtractSURF" -] - -synonims = { - "StarDetector" : ["StarFeatureDetector"], - "MSER" : ["MserFeatureDetector"], - "GFTTDetector" : ["GoodFeaturesToTrackDetector"], - "cvCaptureFromFile" : ["cvCreateFileCapture"], - "cvCaptureFromCAM" : ["cvCreateCameraCapture"], - "cvCalcArrBackProjectPatch" : ["cvCalcBackProjectPatch"], - "cvCalcArrBackProject" : ["cvCalcBackProject"], - "InputArray" : ["_InputArray"], - "OutputArray" : ["_OutputArray"], -} - -if do_python_crosscheck: - try: - import cv2 - except ImportError: - print "Could not load cv2" - do_python_crosscheck = False - -def get_cv2_object(name): - if name.startswith("cv2."): - name = name[4:] - if name.startswith("cv."): - name = name[3:] - if name == "Algorithm": - return cv2.Algorithm__create("Feature2D.ORB"), name - elif name == "FeatureDetector": - return cv2.FeatureDetector_create("ORB"), name - elif name == "DescriptorExtractor": - return cv2.DescriptorExtractor_create("ORB"), name - elif name == "BackgroundSubtractor": - return cv2.createBackgroundSubtractorMOG(), name - elif name == "StatModel": - return cv2.KNearest(), name - else: - try: - obj = getattr(cv2, name)() - except AttributeError: - obj = getattr(cv2, "create" + name)() - return obj, name - -def compareSignatures(f, s): - # function names - if f[0] != s[0]: - return False, "name mismatch" - # return type - stype = (s[1] or "void") - ftype = f[1] - stype = re.sub(r"\b(cv|std)::", "", stype) - if ftype: - ftype = re.sub(r"\b(cv|std)::", "", ftype) - if ftype and ftype != stype: - return False, "return type mismatch" - if ("\C" in f[2]) ^ ("\C" in s[2]): - return False, "const qualifier mismatch" - if ("\S" in f[2]) ^ ("\S" in s[2]): - return False, "static qualifier mismatch" - if ("\V" in f[2]) ^ ("\V" in s[2]): - return False, "virtual qualifier mismatch" - if ("\A" in f[2]) ^ ("\A" in s[2]): - return False, "abstract qualifier mismatch" - if len(f[3]) != len(s[3]): - return False, "different number of arguments" - for idx, arg in enumerate(zip(f[3], s[3])): - farg = arg[0] - sarg = arg[1] - ftype = re.sub(r"\b(cv|std)::", "", (farg[0] or "")) - stype = re.sub(r"\b(cv|std)::", "", (sarg[0] or "")) - ftype = re.sub(r"\s+(\*|&)$", "\\1", ftype) - stype = re.sub(r"\s+(\*|&)$", "\\1", stype) - if ftype != stype: - return False, "type of argument #" + str(idx+1) + " mismatch" - fname = farg[1] or "arg" + str(idx) - sname = sarg[1] or "arg" + str(idx) - if fname != sname: - return False, "name of argument #" + str(idx+1) + " mismatch" - fdef = re.sub(r"\b(cv|std)::", "", (farg[2] or "")) - sdef = re.sub(r"\b(cv|std)::", "", (sarg[2] or "")) - if fdef != sdef: - return False, "default value of argument #" + str(idx+1) + " mismatch" - return True, "match" - -def formatSignature(s): - _str = "" - if "/V" in s[2]: - _str += "virtual " - if "/S" in s[2]: - _str += "static " - if s[1]: - _str += s[1] + " " - else: - if not bool(re.match(r"(\w+\.)*(?P\w+)\.(?P=cls)", s[0])): - _str += "void " - if s[0].startswith("cv."): - _str += s[0][3:].replace(".", "::") - else: - _str += s[0].replace(".", "::") - if len(s[3]) == 0: - _str += "()" - else: - _str += "( " - for idx, arg in enumerate(s[3]): - if idx > 0: - _str += ", " - argtype = re.sub(r"\bcv::", "", arg[0]) - argtype = re.sub(r"\s+(\*|&)$", "\\1", arg[0]) - bidx = argtype.find('[') - if bidx < 0: - _str += argtype - else: - _str += argtype[:bidx] - _str += " " - if arg[1]: - _str += arg[1] - else: - _str += "arg" + str(idx) - if bidx >= 0: - _str += argtype[bidx:] - if arg[2]: - _str += "=" + re.sub(r"\bcv::", "", arg[2]) - _str += " )" - if "/C" in s[2]: - _str += " const" - if "/A" in s[2]: - _str += " = 0" - return _str - - -def logerror(code, message, doc = None): - if code in errors_disabled: - return - if doc: - print doc["file"] + ":" + str(doc["line"]), - print "error %03d: %s" % (code, message) - #print - -def process_module(module, path): - hppparser = hp.CppHeaderParser() - rstparser = rp.RstParser(hppparser) - - rstparser.parse(module, path) - rst = rstparser.definitions - - hdrlist = [] - for root, dirs, files in os.walk(os.path.join(path, "include")): - for filename in fnmatch.filter(files, "*.h*"): - hdrlist.append(os.path.join(root, filename)) - - if module == "cuda": - hdrlist.append(os.path.join(path, "..", "core", "include", "opencv2", "core", "cuda_types.hpp")) - hdrlist.append(os.path.join(path, "..", "core", "include", "opencv2", "core", "cuda.hpp")) - hdrlist.append(os.path.join(path, "..", "core", "include", "opencv2", "core", "cuda_stream_accessor.hpp")) - - decls = [] - for hname in hdrlist: - if not "ts_gtest.h" in hname: - decls += hppparser.parse(hname, wmode=False) - - funcs = [] - # not really needed to hardcode all the namespaces. Normally all they are collected automatically - namespaces = ['cv', 'cv.cuda', 'cvflann', 'cvflann.anyimpl', 'cvflann.lsh', 'cv.flann', 'cv.linemod', 'cv.detail', 'cvtest', 'perf', 'cv.videostab'] - classes = [] - structs = [] - - # collect namespaces and classes/structs - for decl in decls: - if decl[0].startswith("const"): - pass - elif decl[0].startswith("class") or decl[0].startswith("struct"): - if decl[0][0] == 'c': - classes.append(decl) - else: - structs.append(decl) - dotIdx = decl[0].rfind('.') - if dotIdx > 0: - namespace = decl[0][decl[0].find(' ')+1:dotIdx] - if not [c for c in classes if c[0].endswith(namespace)] and not [s for s in structs if s[0].endswith(namespace)]: - if namespace not in namespaces: - namespaces.append(namespace) - else: - funcs.append(decl) - - clsnamespaces = [] - # process classes - for cl in classes: - name = cl[0][cl[0].find(' ')+1:] - if name.find('.') < 0 and not name.startswith("Cv"): - logerror(ERROR_004_MISSEDNAMESPACE, "class " + name + " from opencv_" + module + " is placed in global namespace but violates C-style naming convention") - clsnamespaces.append(name) - if do_python_crosscheck and not name.startswith("cv.") and name.startswith("Cv"): - clsnamespaces.append("cv." + name[2:]) - if name.startswith("cv."): - name = name[3:] - name = name.replace(".", "::") - sns = synonims.get(name, []) - sns.append(name) - for name in sns: - doc = rst.get(name) - if not doc: - #TODO: class is not documented - continue - doc[DOCUMENTED_MARKER] = True - # verify class marker - if not doc.get("isclass"): - logerror(ERROR_001_NOTACLASS, "class " + name + " is not marked as \"class\" in documentation", doc) - else: - # verify base - signature = doc.get("class", "") - signature = signature.replace(" public ", " ") - namespaceIdx = signature.rfind("::") - - signature = ("class " + signature).strip() - hdrsignature = ("class " + name + " " + cl[1]).replace(".", "::").replace("cv::","").strip() - if signature != hdrsignature: - logerror(ERROR_003_INCORRECTBASE, "invalid base class documentation\ndocumented: " + signature + "\nactual: " + hdrsignature, doc) - - # process structs - for st in structs: - name = st[0][st[0].find(' ')+1:] - if name.find('.') < 0 and not name.startswith("Cv"): - logerror(ERROR_004_MISSEDNAMESPACE, "struct " + name + " from opencv_" + module + " is placed in global namespace but violates C-style naming convention") - clsnamespaces.append(name) - if name.startswith("cv."): - name = name[3:] - name = name.replace(".", "::") - doc = rst.get(name) - if not doc: - #TODO: struct is not documented - continue - doc[DOCUMENTED_MARKER] = True - # verify struct marker - if not doc.get("isstruct"): - logerror(ERROR_002_NOTASTRUCT, "struct " + name + " is not marked as \"struct\" in documentation", doc) - else: - # verify base - signature = doc.get("class", "") - signature = signature.replace(", public ", " ").replace(" public ", " ") - signature = signature.replace(", protected ", " ").replace(" protected ", " ") - signature = signature.replace(", private ", " ").replace(" private ", " ") - signature = ("struct " + signature).strip() - hdrsignature = (st[0] + " " + st[1]).replace("struct cv.", "struct ").replace(".", "::").strip() - if signature != hdrsignature: - logerror(ERROR_003_INCORRECTBASE, "invalid base struct documentation\ndocumented: " + signature + "\nactual: " + hdrsignature, doc) - print st, doc - - # process functions and methods - flookup = {} - for fn in funcs: - name = fn[0] - parent = None - namespace = None - for cl in clsnamespaces: - if name.startswith(cl + "."): - if cl.startswith(parent or ""): - parent = cl - if parent: - name = name[len(parent) + 1:] - for nm in namespaces: - if parent.startswith(nm + "."): - if nm.startswith(namespace or ""): - namespace = nm - if namespace: - parent = parent[len(namespace) + 1:] - else: - for nm in namespaces: - if name.startswith(nm + "."): - if nm.startswith(namespace or ""): - namespace = nm - if namespace: - name = name[len(namespace) + 1:] - #print namespace, parent, name, fn[0] - if not namespace and not parent and not name.startswith("cv") and not name.startswith("icv") and not name.startswith("CV_"): - logerror(ERROR_004_MISSEDNAMESPACE, "function " + name + " from opencv_" + module + " is placed in global namespace but violates C-style naming convention") - else: - fdescr = (namespace, parent, name, fn) - flookup_entry = flookup.get(fn[0], []) - flookup_entry.append(fdescr) - flookup[fn[0]] = flookup_entry - - if do_python_crosscheck: - pyclsnamespaces = ["cv." + x[3:].replace(".", "_") for x in clsnamespaces] - for name, doc in rst.iteritems(): - decls = doc.get("decls") - if not decls: - continue - for signature in decls: - if signature[0] == "Python1": - pname = signature[1][:signature[1].find('(')] - try: - fn = getattr(cv2.cv, pname[3:]) - docstr = "cv." + fn.__doc__ - except AttributeError: - logerror(ERROR_005_MISSINGPYFUNC, "could not load documented function: cv2." + pname, doc) - continue - docstring = docstr - sign = signature[1] - signature.append(DOCUMENTED_MARKER) - # convert old signature to pydoc style - if docstring.endswith("*"): - docstring = docstring[:-1] - s = None - while s != sign: - s = sign - sign = re.sub(r"^(.*\(.*)\(.*?\)(.*\) *->)", "\\1_\\2", sign) - s = None - while s != sign: - s = sign - sign = re.sub(r"\s*,\s*([^,]+)\s*=\s*[^,]+\s*(( \[.*\])?)\)", " [, \\1\\2])", sign) - sign = re.sub(r"\(\s*([^,]+)\s*=\s*[^,]+\s*(( \[.*\])?)\)", "([\\1\\2])", sign) - - sign = re.sub(r"\)\s*->\s*", ") -> ", sign) - sign = sign.replace("-> convexHull", "-> CvSeq") - sign = sign.replace("-> lines", "-> CvSeq") - sign = sign.replace("-> boundingRects", "-> CvSeq") - sign = sign.replace("-> contours", "-> CvSeq") - sign = sign.replace("-> retval", "-> int") - sign = sign.replace("-> detectedObjects", "-> CvSeqOfCvAvgComp") - - def retvalRplace(match): - m = match.group(1) - m = m.replace("CvScalar", "scalar") - m = m.replace("CvMemStorage", "memstorage") - m = m.replace("ROIplImage", "image") - m = m.replace("IplImage", "image") - m = m.replace("ROCvMat", "mat") - m = m.replace("CvMat", "mat") - m = m.replace("double", "float") - m = m.replace("CvSubdiv2DPoint", "point") - m = m.replace("CvBox2D", "Box2D") - m = m.replace("IplConvKernel", "kernel") - m = m.replace("CvHistogram", "hist") - m = m.replace("CvSize", "width,height") - m = m.replace("cvmatnd", "matND") - m = m.replace("CvSeqOfCvConvexityDefect", "convexityDefects") - mm = m.split(',') - if len(mm) > 1: - return "(" + ", ".join(mm) + ")" - else: - return m - - docstring = re.sub(r"(?<=-> )(.*)$", retvalRplace, docstring) - docstring = docstring.replace("( [, ", "([") - - if sign != docstring: - logerror(ERROR_006_INVALIDPYOLDDOC, "old-style documentation differs from pydoc\npydoc: " + docstring + "\nfixup: " + sign + "\ncvdoc: " + signature[1], doc) - elif signature[0] == "Python2": - pname = signature[1][4:signature[1].find('(')] - cvname = "cv." + pname - parent = None - for cl in pyclsnamespaces: - if cvname.startswith(cl + "."): - if cl.startswith(parent or ""): - parent = cl - try: - if parent: - instance, clsname = get_cv2_object(parent) - fn = getattr(instance, cvname[len(parent)+1:]) - docstr = fn.__doc__ - docprefix = "cv2." + clsname + "." - else: - fn = getattr(cv2, pname) - docstr = fn.__doc__ - docprefix = "cv2." - except AttributeError: - if parent: - logerror(ERROR_005_MISSINGPYFUNC, "could not load documented member of " + parent + " class: cv2." + pname, doc) - else: - logerror(ERROR_005_MISSINGPYFUNC, "could not load documented function cv2." + pname, doc) - signature.append(DOCUMENTED_MARKER) # stop subsequent errors - continue - docstrings = [docprefix + s.replace("([, ", "([") for s in docstr.split(" or ")] - if not signature[1] in docstrings: - pydocs = "\npydoc: ".join(docstrings) - logerror(ERROR_007_INVALIDPYDOC, "documentation differs from pydoc\npydoc: " + pydocs + "\ncvdoc: " + signature[1], doc) - signature.append(DOCUMENTED_MARKER) - - # verify C/C++ signatures - for name, doc in rst.iteritems(): - decls = doc.get("decls") - if not decls: - continue - for signature in decls: - if signature[0] == "C" or signature[0] == "C++": - if "template" in (signature[2][1] or ""): - # TODO find a way to validate templates - signature.append(DOCUMENTED_MARKER) - continue - fd = flookup.get(signature[2][0]) - if not fd: - if signature[2][0].startswith("cv."): - fd = flookup.get(signature[2][0][3:]) - if not fd: - continue - else: - signature[2][0] = signature[2][0][3:] - if signature[0] == "C": - ffd = [f for f in fd if not f[0] and not f[1]] # filter out C++ stuff - if not ffd: - if fd[0][1]: - logerror(ERROR_008_CFUNCISNOTGLOBAL, "function " + fd[0][2] + " is documented as C function but is actually member of " + fd[0][1] + " class", doc) - elif fd[0][0]: - logerror(ERROR_008_CFUNCISNOTGLOBAL, "function " + fd[0][2] + " is documented as C function but is actually placed in " + fd[0][0] + " namespace", doc) - fd = ffd - error = None - for f in fd: - match, error = compareSignatures(signature[2], f[3]) - if match: - signature.append(DOCUMENTED_MARKER) - break - if signature[-1] != DOCUMENTED_MARKER: - candidates = "\n\t".join([formatSignature(f[3]) for f in fd]) - logerror(ERROR_009_OVERLOADNOTFOUND, signature[0] + " function " + signature[2][0].replace(".","::") + " is documented but misses in headers (" + error + ").\nDocumented as:\n\t" + signature[1] + "\nCandidates are:\n\t" + candidates, doc) - signature.append(DOCUMENTED_MARKER) # to stop subsequent error on this function - - # verify that all signatures was found in the library headers - for name, doc in rst.iteritems(): - # if doc.get(DOCUMENTED_MARKER, False): - # continue # this class/struct was found - if not doc.get(DOCUMENTED_MARKER, False) and (doc.get("isclass", False) or doc.get("isstruct", False)): - if name in doc_signatures_whitelist: - continue - logerror(ERROR_010_UNKNOWNCLASS, "class/struct " + name + " is mentioned in documentation but is not found in OpenCV headers", doc) - for d in doc.get("decls", []): - if d[-1] != DOCUMENTED_MARKER: - if d[0] == "C" or d[0] =="C++" or (do_python_crosscheck and d[0].startswith("Python")): - if d[0][0] == 'C': - sname = d[2][0][3:].replace(".", "::") - if sname in defines: - #TODO: need to find a way to verify #define's - continue - else: - sname = d[1][:d[1].find("(")] - prefixes = [x for x in doc_signatures_whitelist if sname.startswith(x)] - if prefixes: - # TODO: member of template class - continue - logerror(ERROR_011_UNKNOWNFUNC, d[0] + " function " + sname + " is documented but is not found in OpenCV headers. It is documented as:\n\t" + d[1], doc) - # end of process_module - -if __name__ == "__main__": - if len(sys.argv) < 2: - print "Usage:\n", os.path.basename(sys.argv[0]), " " - exit(0) - - modules = sys.argv[1:] - if modules[0] == "all": - modules = allmodules - - for module in modules: - selfpath = os.path.dirname(os.path.abspath(sys.argv[0])) - module_path = os.path.join(selfpath, "..", "modules", module) - - if not os.path.isdir(module_path): - print "Module \"" + module + "\" could not be found." - exit(1) - - process_module(module, module_path) diff --git a/doc/check_docs_whitelist.txt b/doc/check_docs_whitelist.txt deleted file mode 100644 index 8359178b96..0000000000 --- a/doc/check_docs_whitelist.txt +++ /dev/null @@ -1,193 +0,0 @@ -# this is a list of functions, classes and methods -# that are not supposed to be documented in the near future, -# to make the output of check_docs.py script more sensible. -# -# Syntax: -# every line starting with # is a comment -# there can be empty lines -# each line includes either a class name (including all the necessary namespaces), -# or a function/method name -# or a full declaration of a function/method -# if a class name is in the whitelist, all the methods are considered "white-listed" too -# if a method/function name is listed, then all the overload variants are "white-listed". -# that is, to white list a particular overloaded variant of a function/method you need to put -# full declaration into the file -# - -######################################### core ##################################### -cv::Mat::MSize -cv::Mat::MStep -cv::MatConstIterator -cv::NAryMatIterator -cv::Algorithm -cv::_InputArray -cv::_OutputArray - -######################################## imgproc ################################### -CvLSHOperations -cv::FilterEngine -cv::BaseFilter -cv::BaseRowFilter -cv::BaseColumnFilter -cv::Moments - -###################################### features2d################################### -cv::BOWKMeansTrainer::cluster -cv::BOWTrainer::BOWTrainer -cv::BOWTrainer::clear -cv::AdjusterAdapter::clone - -cv::MSER::MSER -cv::StarDetector::StarDetector -cv::SIFT::CommonParams::CommonParams -cv::SIFT::SIFT -cv::SURF::SURF -cv::SimpleBlobDetector::Params::Params - -cv::FastFeatureDetector::read -cv::MserFeatureDetector::read -cv::StarFeatureDetector::read -cv::SurfFeatureDetector::read -cv::SiftFeatureDetector::read -cv::GoodFeaturesToTrackDetector::read -cv::OrbFeatureDetector::read - -cv::FastFeatureDetector::write -cv::MserFeatureDetector::write -cv::StarFeatureDetector::write -cv::SurfFeatureDetector::write -cv::SiftFeatureDetector::write -cv::GoodFeaturesToTrackDetector::write -cv::OrbFeatureDetector::write - -cv::DynamicAdaptedFeatureDetector::empty -cv::GridAdaptedFeatureDetector::empty -cv::PyramidAdaptedFeatureDetector::empty - -cv::BriefDescriptorExtractor::descriptorSize -cv::SurfDescriptorExtractor::descriptorSize -cv::SiftDescriptorExtractor::descriptorSize -cv::OpponentColorDescriptorExtractor::descriptorSize -cv::OrbDescriptorExtractor::descriptorSize - -cv::BriefDescriptorExtractor::descriptorType -cv::SurfDescriptorExtractor::descriptorType -cv::SiftDescriptorExtractor::descriptorType -cv::OpponentColorDescriptorExtractor::descriptorType -cv::OrbDescriptorExtractor::descriptorType - -cv::SurfDescriptorExtractor::read -cv::SiftDescriptorExtractor::read -cv::OpponentColorDescriptorExtractor::read -cv::OrbDescriptorExtractor::read - -cv::SurfDescriptorExtractor::write -cv::SiftDescriptorExtractor::write -cv::OpponentColorDescriptorExtractor::write -cv::OrbDescriptorExtractor::write - -cv::OpponentColorDescriptorExtractor::empty - -cv::FlannBasedMatcher::train - -cv::FlannBasedMatcher::clear - -cv::FlannBasedMatcher::clone - -cv::FlannBasedMatcher::isMaskSupported - - -cv::GenericDescriptorMatcher::GenericDescriptorMatcher - -cv::VectorDescriptorMatcher::clear -cv::FernDescriptorMatcher::clear -cv::OneWayDescriptorMatcher::clear - -cv::VectorDescriptorMatcher::empty -cv::FernDescriptorMatcher::empty -cv::OneWayDescriptorMatcher::empty - -cv::OneWayDescriptorMatcher::read - -cv::VectorDescriptorMatcher::isMaskSupported -cv::FernDescriptorMatcher::isMaskSupported -cv::OneWayDescriptorMatcher::isMaskSupported - -cv::VectorDescriptorMatcher::train -cv::FernDescriptorMatcher::train -cv::OneWayDescriptorMatcher::train - -cv::VectorDescriptorMatcher::read -cv::FernDescriptorMatcher::read - -cv::VectorDescriptorMatcher::write -cv::FernDescriptorMatcher::write -cv::OneWayDescriptorMatcher::write - - - -cv::FastAdjuster::good -cv::StarAdjuster::good -cv::SurfAdjuster::good -cv::FastAdjuster::tooFew -cv::StarAdjuster::tooFew -cv::SurfAdjuster::tooFew -cv::FastAdjuster::tooMany -cv::StarAdjuster::tooMany -cv::SurfAdjuster::tooMany -cv::FastAdjuster::clone -cv::StarAdjuster::clone -cv::SurfAdjuster::clone - -######################################## calib3d ################################### -CvLevMarq -Mat cv::findFundamentalMat( InputArray points1, InputArray points2, OutputArray mask, int method=FM_RANSAC, double param1=3., double param2=0.99) -Mat findHomography( InputArray srcPoints, InputArray dstPoints, OutputArray mask, int method=0, double ransacReprojThreshold=3); - -########################################## ml ###################################### -CvBoostTree -CvForestTree -CvSVMKernel -CvSVMSolver -CvDTreeTrainData -CvERTreeTrainData -CvKNearest::CvKNearest -CvKNearest::clear -CvDTreeNode::get_num_valid -CvDTreeNode::set_num_valid -CvDTree::CvDTree -CvDTree::clear -CvDTree::read -CvDTree::write -CvEM::CvEM -CvEM::clear -CvEM::read -CvEM::write -CvSVM::CvSVM -CvSVM::clear -CvSVM::read -CvSVM::write -CvMLData::CvMLData -CvRTrees::CvRTrees -CvRTrees::clear -CvRTrees::read -CvRTrees::write -CvBoost::CvBoost -CvBoost::clear -CvBoost::read -CvBoost::write -CvGBTrees::CvGBTrees -CvGBTrees::clear -CvGBTrees::read -CvGBTrees::write -CvNormalBayesClassifier::CvNormalBayerClassifier -CvNormalBayesClassifier::clear -CvNormalBayesClassifier::read -CvNormalBayesClassifier::write -CvANN_MLP::CvANN_MLP -CvANN_MLP::clear -CvANN_MLP::read -CvANN_MLP::write -CvTrainTestSplit -cvParamLattice -cvDefaultParamLattice diff --git a/doc/conf.py b/doc/conf.py deleted file mode 100755 index 97d0b6facb..0000000000 --- a/doc/conf.py +++ /dev/null @@ -1,428 +0,0 @@ -#!/usr/bin/env python - -# -*- coding: utf-8 -*- -# -# opencvstd documentation build configuration file, created by -# sphinx-quickstart on Mon Feb 14 00:30:43 2011. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os, re - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.todo', 'sphinx.ext.extlinks', 'ocv', 'sphinx.ext.doctest'] - -have_plantuml_ext = False -if tags.has('plantuml'): - try: - import sphinxcontrib.plantuml - extensions.append("sphinxcontrib.plantuml") - have_plantuml_ext = True - except ImportError: - print "No module sphinxcontrib.plantuml found, sphinx will not render UML diagrams" - -doctest_test_doctest_blocks = 'block' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'OpenCV' -copyright = u'2011-2014, opencv dev team' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. - -version_file = open("../modules/core/include/opencv2/core/version.hpp", "rt").read() -version_major = re.search("^W*#\W*define\W+CV_VERSION_MAJOR\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) -version_minor = re.search("^W*#\W*define\W+CV_VERSION_MINOR\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) -version_patch = re.search("^W*#\W*define\W+CV_VERSION_REVISION\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) -version_status = re.search("^W*#\W*define\W+CV_VERSION_STATUS\W+\"(.*?)\"\W*$", version_file, re.MULTILINE).group(1) - -# The short X.Y version. -version = version_major + '.' + version_minor -# The full version, including alpha/beta/rc tags. -release = version_major + '.' + version_minor + '.' + version_patch + version_status - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['doc/tutorials/definitions'] - -if not have_plantuml_ext: - exclude_patterns.append('**/uml/*') - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -todo_include_todos=True - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'sphinxdoc' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ['_themes'] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -html_logo = 'opencv-logo2.png' - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'opencv' - -# OpenCV docs use some custom LaTeX macros in the formula. Make sure we include the definitions -pngmath_latex_preamble = r""" -\usepackage{euler}\usepackage[usenames,dvipsnames]{color}\usepackage{amssymb}\usepackage{amsmath}\usepackage{bbm}\usepackage{colortbl} -\newcommand{\matTT}[9]{ -\[ -\left|\begin{array}{ccc} - #1 & #2 & #3\\ - #4 & #5 & #6\\ - #7 & #8 & #9 -\end{array}\right| -\] -} - -\newcommand{\fork}[4]{ - \left\{ - \begin{array}{l l} - #1 & \mbox{#2}\\ - #3 & \mbox{#4}\\ - \end{array} \right.} -\newcommand{\forkthree}[6]{ - \left\{ - \begin{array}{l l} - #1 & \mbox{#2}\\ - #3 & \mbox{#4}\\ - #5 & \mbox{#6}\\ - \end{array} \right.} - -\newcommand{\vecthree}[3]{ -\begin{bmatrix} - #1\\ - #2\\ - #3 -\end{bmatrix} -} - -\newcommand{\vecthreethree}[9]{ -\begin{bmatrix} - #1 & #2 & #3\\ - #4 & #5 & #6\\ - #7 & #8 & #9 -\end{bmatrix} -} -""" - -# -- Options for LaTeX output -------------------------------------------------- - -# The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('modules/refman', 'opencv2refman.tex', u'The OpenCV Reference Manual', - u'', 'manual'), - ('doc/user_guide/user_guide', 'opencv_user.tex', u'The OpenCV User Guide', - u'', 'manual'), - ('doc/tutorials/tutorials', 'opencv_tutorials.tex', u'The OpenCV Tutorials', - u'', 'manual'), - ('platforms/android/refman', 'opencv2manager.tex', u'The OpenCV Manager Manual', - u'', 'manual'), -] - -preamble =""" -\usepackage{euler} -\usepackage[scaled=0.85]{beramono} -\usepackage{mymath}\usepackage{amssymb}\usepackage{amsmath}\usepackage{bbm}\setcounter{secnumdepth}{1} -\usepackage{colortbl} -\usepackage{enumitem} -\setlist{labelsep=1ex} -""" - -latex_elements = {'preamble': preamble} - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Additional stuff for the LaTeX preamble. -#latex_preamble = '' - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'opencv', u'The OpenCV Reference Manual', - [u'admin@opencv.org'], 1) -] - -# ---- External links for tutorials ----------------- -extlinks = { - 'basicstructures' : ('http://docs.opencv.org/modules/core/doc/basic_structures.html#%s', None), - 'oldbasicstructures' : ('http://docs.opencv.org/modules/core/doc/old_basic_structures.html#%s', None), - 'readwriteimage' : ('http://docs.opencv.org/modules/imgcodecs/doc/reading_and_writing_images.html#%s', None), - 'readwritevideo' : ('http://docs.opencv.org/modules/videoio/doc/reading_and_writing_video.html#%s', None), - 'operationsonarrays' : ('http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#%s', None), - 'utilitysystemfunctions' : ('http://docs.opencv.org/modules/core/doc/utility_and_system_functions_and_macros.html#%s', None), - 'imgprocfilter' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html#%s', None), - 'svms' : ('http://docs.opencv.org/modules/ml/doc/support_vector_machines.html#%s', None), - 'drawingfunc' : ('http://docs.opencv.org/modules/core/doc/drawing_functions.html#%s', None), - 'xmlymlpers' : ('http://docs.opencv.org/modules/core/doc/xml_yaml_persistence.html#%s', None), - 'rwimg' : ('http://docs.opencv.org/modules/imgcodecs/doc/reading_and_writing_images.html#%s', None), - 'hgvideo' : ('http://docs.opencv.org/modules/videoio/doc/reading_and_writing_video.html#%s', None), - 'gpuinit' : ('http://docs.opencv.org/modules/gpu/doc/initalization_and_information.html#%s', None), - 'gpudatastructure' : ('http://docs.opencv.org/modules/gpu/doc/data_structures.html#%s', None), - 'gpuopmatrices' : ('http://docs.opencv.org/modules/gpu/doc/operations_on_matrices.html#%s', None), - 'gpuperelement' : ('http://docs.opencv.org/modules/gpu/doc/per_element_operations.html#%s', None), - 'gpuimgproc' : ('http://docs.opencv.org/modules/gpu/doc/image_processing.html#%s', None), - 'gpumatrixreduct' : ('http://docs.opencv.org/modules/gpu/doc/matrix_reductions.html#%s', None), - 'filtering' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html#%s', None), - 'flann' : ('http://docs.opencv.org/modules/flann/doc/flann_fast_approximate_nearest_neighbor_search.html#%s', None ), - 'calib3d' : ('http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#%s', None ), - 'feature2d' : ('http://docs.opencv.org/modules/imgproc/doc/feature_detection.html#%s', None ), - 'imgproc_geometric' : ('http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html#%s', None ), - 'miscellaneous_transformations' : ('http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#%s', None), - 'user_interface' : ('http://docs.opencv.org/modules/highgui/doc/user_interface.html#%s', None), - 'video' : ('http://docs.opencv.org/modules/video/doc/motion_analysis_and_object_tracking.html#%s', None), - - # 'opencv_group' : ('http://answers.opencv.org/%s', None), - 'opencv_qa' : ('http://answers.opencv.org/%s', None), - 'how_to_contribute' : ('http://code.opencv.org/projects/opencv/wiki/How_to_contribute/%s', None), - - 'cvt_color' : ('http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html?highlight=cvtcolor#cvtcolor%s', None), - 'imread' : ('http://docs.opencv.org/modules/imgcodecs/doc/reading_and_writing_images.html?highlight=imread#imread%s', None), - 'imwrite' : ('http://docs.opencv.org/modules/imgcodecs/doc/reading_and_writing_images.html?highlight=imwrite#imwrite%s', None), - 'imshow' : ('http://docs.opencv.org/modules/highgui/doc/user_interface.html?highlight=imshow#imshow%s', None), - 'named_window' : ('http://docs.opencv.org/modules/highgui/doc/user_interface.html?highlight=namedwindow#namedwindow%s', None), - 'wait_key' : ('http://docs.opencv.org/modules/highgui/doc/user_interface.html?highlight=waitkey#waitkey%s', None), - 'add_weighted' : ('http://docs.opencv.org/modules/core/doc/operations_on_arrays.html?highlight=addweighted#addweighted%s', None), - 'saturate_cast' : ('http://docs.opencv.org/modules/core/doc/utility_and_system_functions_and_macros.html?highlight=saturate_cast#saturate-cast%s', None), - 'mat_zeros' : ('http://docs.opencv.org/modules/core/doc/basic_structures.html?highlight=zeros#mat-zeros%s', None), - 'convert_to' : ('http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-convertto%s', None), - 'create_trackbar' : ('http://docs.opencv.org/modules/highgui/doc/user_interface.html?highlight=createtrackbar#createtrackbar%s', None), - 'point' : ('http://docs.opencv.org/modules/core/doc/basic_structures.html#point%s', None), - 'scalar' : ('http://docs.opencv.org/modules/core/doc/basic_structures.html#scalar%s', None), - 'line' : ('http://docs.opencv.org/modules/core/doc/drawing_functions.html#line%s', None), - 'ellipse' : ('http://docs.opencv.org/modules/core/doc/drawing_functions.html#ellipse%s', None), - 'rectangle' : ('http://docs.opencv.org/modules/core/doc/drawing_functions.html#rectangle%s', None), - 'circle' : ('http://docs.opencv.org/modules/core/doc/drawing_functions.html#circle%s', None), - 'fill_poly' : ('http://docs.opencv.org/modules/core/doc/drawing_functions.html#fillpoly%s', None), - 'rng' : ('http://docs.opencv.org/modules/core/doc/operations_on_arrays.html?highlight=rng#rng%s', None), - 'put_text' : ('http://docs.opencv.org/modules/core/doc/drawing_functions.html#puttext%s', None), - 'gaussian_blur' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=gaussianblur#gaussianblur%s', None), - 'blur' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=blur#blur%s', None), - 'median_blur' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=medianblur#medianblur%s', None), - 'bilateral_filter' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=bilateralfilter#bilateralfilter%s', None), - 'erode' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=erode#erode%s', None), - 'dilate' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=dilate#dilate%s', None), - 'get_structuring_element' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=getstructuringelement#getstructuringelement%s', None), - 'flood_fill' : ( 'http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html?highlight=floodfill#floodfill%s', None), - 'morphology_ex' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=morphologyex#morphologyex%s', None), - 'pyr_down' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=pyrdown#pyrdown%s', None), - 'pyr_up' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=pyrup#pyrup%s', None), - 'resize' : ('http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html?highlight=resize#resize%s', None), - 'threshold' : ('http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html?highlight=threshold#threshold%s', None), - 'filter2d' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=filter2d#filter2d%s', None), - 'copy_make_border' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=copymakeborder#copymakeborder%s', None), - 'sobel' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=sobel#sobel%s', None), - 'scharr' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=scharr#scharr%s', None), - 'laplacian' : ('http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=laplacian#laplacian%s', None), - 'canny' : ('http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=canny#canny%s', None), - 'copy_to' : ('http://docs.opencv.org/modules/core/doc/basic_structures.html?highlight=copyto#mat-copyto%s', None), - 'hough_lines' : ('http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=houghlines#houghlines%s', None), - 'hough_lines_p' : ('http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=houghlinesp#houghlinesp%s', None), - 'hough_circles' : ('http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=houghcircles#houghcircles%s', None), - 'remap' : ('http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html?highlight=remap#remap%s', None), - 'warp_affine' : ('http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html?highlight=warpaffine#warpaffine%s' , None), - 'get_rotation_matrix_2d' : ('http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html?highlight=getrotationmatrix2d#getrotationmatrix2d%s', None), - 'get_affine_transform' : ('http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html?highlight=getaffinetransform#getaffinetransform%s', None), - 'equalize_hist' : ('http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=equalizehist#equalizehist%s', None), - 'split' : ('http://docs.opencv.org/modules/core/doc/operations_on_arrays.html?highlight=split#split%s', None), - 'calc_hist' : ('http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=calchist#calchist%s', None), - 'normalize' : ('http://docs.opencv.org/modules/core/doc/operations_on_arrays.html?highlight=normalize#normalize%s', None), - 'match_template' : ('http://docs.opencv.org/modules/imgproc/doc/object_detection.html?highlight=matchtemplate#matchtemplate%s', None), - 'min_max_loc' : ('http://docs.opencv.org/modules/core/doc/operations_on_arrays.html?highlight=minmaxloc#minmaxloc%s', None), - 'mix_channels' : ( 'http://docs.opencv.org/modules/core/doc/operations_on_arrays.html?highlight=mixchannels#mixchannels%s', None), - 'calc_back_project' : ('http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=calcbackproject#calcbackproject%s', None), - 'compare_hist' : ('http://docs.opencv.org/modules/imgproc/doc/histograms.html?highlight=comparehist#comparehist%s', None), - 'corner_harris' : ('http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=cornerharris#cornerharris%s', None), - 'good_features_to_track' : ('http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=goodfeaturestotrack#goodfeaturestotrack%s', None), - 'corner_min_eigenval' : ('http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=cornermineigenval#cornermineigenval%s', None), - 'corner_eigenvals_and_vecs' : ('http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=cornereigenvalsandvecs#cornereigenvalsandvecs%s', None), - 'corner_sub_pix' : ('http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=cornersubpix#cornersubpix%s', None), - 'find_contours' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours%s', None), - 'convex_hull' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=convexhull#convexhull%s', None), - 'draw_contours' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=drawcontours#drawcontours%s', None), - 'bounding_rect' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=boundingrect#boundingrect%s', None), - 'min_enclosing_circle' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=minenclosingcircle#minenclosingcircle%s', None), - 'min_area_rect' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=minarearect#minarearect%s', None), - 'fit_ellipse' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=fitellipse#fitellipse%s', None), - 'moments' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=moments#moments%s', None), - 'contour_area' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=contourarea#contourarea%s', None), - 'arc_length' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=arclength#arclength%s', None), - 'point_polygon_test' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=pointpolygontest#pointpolygontest%s', None), - 'feature_detection_and_description' : ('http://docs.opencv.org/modules/features2d/doc/feature_detection_and_description.html#%s', None), - 'feature_detector' : ( 'http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_feature_detectors.html?highlight=featuredetector#FeatureDetector%s', None), - 'feature_detector_detect' : ('http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_feature_detectors.html?highlight=detect#featuredetector-detect%s', None ), - 'surf_feature_detector' : ('http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_feature_detectors.html?highlight=surffeaturedetector#surffeaturedetector%s', None ), - 'draw_keypoints' : ('http://docs.opencv.org/modules/features2d/doc/drawing_function_of_keypoints_and_matches.html?highlight=drawkeypoints#drawkeypoints%s', None ), - 'descriptor_extractor': ( 'http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_descriptor_extractors.html?highlight=descriptorextractor#descriptorextractor%s', None ), - 'descriptor_extractor_compute' : ( 'http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_descriptor_extractors.html?highlight=compute#descriptorextractor-compute%s', None ), - 'surf_descriptor_extractor' : ( 'http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_descriptor_extractors.html?highlight=surfdescriptorextractor#surfdescriptorextractor%s', None ), - 'draw_matches' : ( 'http://docs.opencv.org/modules/features2d/doc/drawing_function_of_keypoints_and_matches.html?highlight=drawmatches#drawmatches%s', None ), - 'find_homography' : ('http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html?highlight=findhomography#findhomography%s', None), - 'perspective_transform' : ('http://docs.opencv.org/modules/core/doc/operations_on_arrays.html?highlight=perspectivetransform#perspectivetransform%s', None ), - 'flann_based_matcher' : ('http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_descriptor_matchers.html?highlight=flannbasedmatcher#flannbasedmatcher%s', None), - 'brute_force_matcher' : ('http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_descriptor_matchers.html?highlight=bruteforcematcher#bruteforcematcher%s', None ), - 'cascade_classifier' : ('http://docs.opencv.org/modules/objdetect/doc/cascade_classification.html?highlight=cascadeclassifier#cascadeclassifier%s', None ), - 'cascade_classifier_load' : ('http://docs.opencv.org/modules/objdetect/doc/cascade_classification.html?highlight=load#cascadeclassifier-load%s', None ), - 'cascade_classifier_detect_multiscale' : ('http://docs.opencv.org/modules/objdetect/doc/cascade_classification.html?highlight=detectmultiscale#cascadeclassifier-detectmultiscale%s', None ), - 'background_subtractor' : ('http://docs.opencv.org/modules/video/doc/motion_analysis_and_object_tracking.html?highlight=backgroundsubtractor#backgroundsubtractor%s', None), - 'background_subtractor_mog' : ('http://docs.opencv.org/modules/video/doc/motion_analysis_and_object_tracking.html?highlight=backgroundsubtractorMOG#backgroundsubtractormog%s', None), - 'background_subtractor_mog_two' : ('http://docs.opencv.org/modules/video/doc/motion_analysis_and_object_tracking.html?highlight=backgroundsubtractorMOG2#backgroundsubtractormog2%s', None), - 'video_capture' : ('http://docs.opencv.org/modules/videoio/doc/reading_and_writing_video.html?highlight=videocapture#videocapture%s', None), - 'ippa_convert': ('http://docs.opencv.org/modules/core/doc/ipp_async_converters.html#%s', None), - 'ptr':('http://docs.opencv.org/modules/core/doc/basic_structures.html?highlight=Ptr#Ptr%s', None) - } diff --git a/doc/footer.html b/doc/footer.html new file mode 100644 index 0000000000..e9a2ed7d93 --- /dev/null +++ b/doc/footer.html @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/doc/haartraining.htm b/doc/haartraining.htm deleted file mode 100644 index 9a0767d26f..0000000000 --- a/doc/haartraining.htm +++ /dev/null @@ -1,676 +0,0 @@ - - - - - -Object Detection Using Haar-like Features with Cascade of Boosted -Classifiers - - - - - - -
- -

Rapid Object Detection With A Cascade of Boosted -Classifiers Based on Haar-like Features

- -

Introduction

- -

This document describes how to train and -use a cascade of boosted classifiers for rapid object detection. A large set of -over-complete haar-like features provide the basis for the simple individual -classifiers. Examples of object detection tasks are face, eye and nose -detection, as well as logo detection.

- -

 

- -

The sample detection task in this document -is logo detection, since logo detection does not require the collection of -large set of registered and carefully marked object samples. Instead we assume -that from one prototype image, a very large set of derived object examples can -be derived (createsamples utility, see below).

- -

 

- -

A detailed description of the training/evaluation -algorithm can be found in [1] and [2].

- -

Samples Creation

- -

For training a training samples must be -collected. There are two sample types: negative samples and positive samples. -Negative samples correspond to non-object images. Positive samples correspond -to object images.

- -

Negative Samples

- -

Negative samples are taken from arbitrary -images. These images must not contain object representations. Negative samples -are passed through background description file. It is a text file in which each -text line contains the filename (relative to the directory of the description -file) of negative sample image. This file must be created manually. Note that -the negative samples and sample images are also called background samples or -background samples images, and are used interchangeably in this document

- -

 

- -

Example of negative description file:

- -

 

- -

Directory structure:

- -

/img

- -

  img1.jpg

- -

  img2.jpg

- -

bg.txt

- -

 

- -

File bg.txt:

- -

img/img1.jpg

- -

img/img2.jpg

- -

Positive Samples

- -

Positive samples are created by createsamples -utility. They may be created from single object image or from collection of -previously marked up images.
-
-

- -

The single object image may for instance -contain a company logo. Then are large set of positive samples are created from -the given object image by randomly rotating, changing the logo color as well as -placing the logo on arbitrary background.

- -

The amount and range of randomness can be -controlled by command line arguments.

- -

Command line arguments:

- -

- vec <vec_file_name>

- -

name of the -output file containing the positive samples for training

- -

- img <image_file_name>

- -

source object -image (e.g., a company logo)

- -

- bg <background_file_name>

- -

background -description file; contains a list of images into which randomly distorted -versions of the object are pasted for positive sample generation

- -

- num <number_of_samples>

- -

number of -positive samples to generate

- -

- bgcolor <background_color>

- -

      background color (currently grayscale images are assumed); the -background color denotes the transparent color. Since there might be -compression artifacts, the amount of color tolerance can be specified by –bgthresh. All pixels between bgcolor-bgthresh and bgcolor+bgthresh are regarded as transparent.

- -

- bgthresh <background_color_threshold>

- -

- inv

- -

      if specified, the colors will be inverted

- -

- randinv

- -

      if specified, the colors will be inverted randomly

- -

- maxidev <max_intensity_deviation>

- -

  maximal -intensity deviation of foreground samples pixels

- -

- maxxangle <max_x_rotation_angle>,

- -

- maxyangle <max_y_rotation_angle>,

- -

- maxzangle <max_z_rotation_angle>

- -

      maximum rotation angles in radians

- -

-show

- -

      if specified, each sample will be shown. Pressing ‘Esc’ will -continue creation process without samples showing. Useful debugging option.

- -

- w <sample_width>

- -

  width (in -pixels) of the output samples

- -

- h <sample_height>

- -

  height (in -pixels) of the output samples

- -

 

- -

For following procedure is used to create a -sample object instance:

- -

The source image is rotated random around -all three axes. The chosen angle is limited my -max?angle. Next pixels of -intensities in the range of [bg_color-bg_color_threshold; -bg_color+bg_color_threshold] are regarded as -transparent. White noise is added to the intensities of the foreground. If –inv key is -specified then foreground pixel intensities are inverted. If –randinv key is -specified then it is randomly selected whether for this sample inversion will -be applied. Finally, the obtained image is placed onto arbitrary background -from the background description file, resized to the pixel size specified by –w and –h and stored -into the file specified by the –vec command line parameter.

- -

 

- -

Positive samples also may be obtained from -a collection of previously marked up images. This collection is described by -text file similar to background description file. Each line of this file -corresponds to collection image. The first element of the line is image file -name. It is followed by number of object instances. The following numbers are -the coordinates of bounding rectangles (x, y, width, height).

- -

 

- -

Example of description file:

- -

 

- -

Directory structure:

- -

/img

- -

  img1.jpg

- -

  img2.jpg

- -

info.dat

- -

 

- -

File info.dat:

- -

img/img1.jpg  1  140 -100 45 45

- -

img/img2.jpg  2  100 -200 50 50   50 30 25 25

- -

 

- -

Image img1.jpg contains single object -instance with bounding rectangle (140, 100, 45, 45). Image img2.jpg contains -two object instances.

- -

 

- -

In order to create positive samples from -such collection –info argument should be specified instead of –img:

- -

- info <collection_file_name>

- -

description file -of marked up images collection

- -

 

- -

The scheme of sample creation in this case -is as follows. The object instances are taken from images. Then they are -resized to samples size and stored in output file. No distortion is applied, so -the only affecting arguments are –w, -h, -show and –num.

- -

 

- -

createsamples utility may be used for examining samples stored in positive samples -file. In order to do this only –vec, –w and –h parameters -should be specified.

- -

 

- -

Note that for training, it does not matter -how positive samples files are generated. So the createsamples utility is only one way -to collect/create a vector file of positive samples.

- -

Training

- -

The next step after samples creation is -training of classifier. It is performed by the haartraining utility.

- -

 

- -

Command line arguments:

- -

- data <dir_name>

- -

      directory name in which the trained classifier is stored

- -

- vec <vec_file_name>

- -

      file name of positive sample file (created by trainingsamples utility or by any other means)

- -

- bg <background_file_name>

- -

      background description file

- -

- npos <number_of_positive_samples>,

- -

- nneg <number_of_negative_samples>

- -

      number of positive/negative samples used in training of each -classifier stage. Reasonable values are npos = 7000 and nneg = 3000.

- -

- nstages <number_of_stages>

- -

  number of -stages to be trained

- -

- nsplits <number_of_splits>

- -

      determines the weak classifier used in stage classifiers. If 1, then a simple stump classifier is used, if 2 and more, then CART classifier with number_of_splits internal (split) -nodes is used

- -

- mem <memory_in_MB>

- -

      Available memory in MB for precalculation. The more memory you -have the faster the training process

- -

- sym (default),

- -

- nonsym

- -

      specifies whether the object class under training has vertical -symmetry or not. Vertical symmetry speeds up training process. For instance, -frontal faces show off vertical symmetry

- -

- minhitrate <min_hit_rate>

- -

      minimal desired hit rate for each stage classifier. Overall hit -rate may be estimated as (min_hit_rate^number_of_stages)

- -

- maxfalsealarm <max_false_alarm_rate>

- -

      maximal desired false alarm rate for each stage classifier. Overall -false alarm rate may be estimated as (max_false_alarm_rate^number_of_stages)

- -

- weighttrimming <weight_trimming>

- -

  Specifies -whether and how much weight trimming should be used. A decent choice is 0.90.

- -

- eqw

- -

- mode <BASIC (default) | CORE | ALL>

- -

      selects the type of haar features set used in training. BASIC use -only upright features, while ALL uses the full set of upright and 45 degree -rotated feature set. See [1] for more details.

- -

- w <sample_width>,

- -

- h <sample_height>

- -

      Size of training samples (in pixels). Must have exactly the same -values as used during training samples creation (utility trainingsamples)

- -

 

- -

Note: in order to use multiprocessor -advantage a compiler that supports OpenMP 1.0 standard should be used.

- -

Application

- -

OpenCV cvHaarDetectObjects() function (in -particular haarFaceDetect demo) is used for detection.

- -

Test Samples

- -

In order to evaluate the performance of -trained classifier a collection of marked up images is needed. When such -collection is not available test samples may be created from single object -image by createsamples utility. The scheme of test samples creation in this case is -similar to training samples creation since each test sample is a background -image into which a randomly distorted and randomly scaled instance of the -object picture is pasted at a random position.

- -

 

- -

If both –img and –info arguments are specified then -test samples will be created by createsamples utility. The sample image is arbitrary distorted as it was -described below, then it is placed at random location to background image and -stored. The corresponding description line is added to the file specified by –info argument.

- -

 

- -

The –w and –h keys determine the minimal size of -placed object picture.

- -

 

- -

The test image file name format is as -follows:

- -

imageOrderNumber_x_y_width_height.jpg, where x, y, width and height are the coordinates of placed object bounding rectangle.

- -

Note that you should use a background -images set different from the background image set used during training.

- -

Performance -Evaluation

- -

In order to evaluate the performance of the -classifier performance utility may be used. It takes a collection of marked up images, -applies the classifier and outputs the performance, i.e. number of found -objects, number of missed objects, number of false alarms and other -information.

- -

 

- -

Command line arguments:

- -

- data <dir_name>

- -

      directory name in which the trained classifier is stored

- -

- info <collection_file_name>

- -

      file with test samples description

- -

- maxSizeDiff <max_size_difference>,

- -

- maxPosDiff <max_position_difference>

- -

      determine the criterion of reference and detected rectangles -coincidence. Default values are 1.5 and 0.3 respectively.

- -

- sf <scale_factor>,

- -

      detection parameter. Default value is 1.2.

- -

- w <sample_width>,

- -

- h <sample_height>

- -

      Size of training samples (in pixels). Must have exactly the same -values as used during training (utility haartraining)

- -

References

- -

[1] Rainer Lienhart and Jochen Maydt. An -Extended Set of Haar-like Features for Rapid Object Detection. Submitted to -ICIP2002.

- -

[2] Alexander Kuranov, Rainer Lienhart, and -Vadim Pisarevsky. An Empirical Analysis of Boosting Algorithms for Rapid -Objects With an Extended Set of Haar-like Features. Intel Technical Report -MRL-TR-July02-01, 2002.

- -
- - - - diff --git a/doc/header.html b/doc/header.html new file mode 100644 index 0000000000..55f2ea171c --- /dev/null +++ b/doc/header.html @@ -0,0 +1,56 @@ + + + + + + + +$projectname: $title +$title + + + + +$treeview +$search +$mathjax + +$extrastylesheet + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+
$projectname +  $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
+
+ + diff --git a/doc/ocv.py b/doc/ocv.py deleted file mode 100755 index a22d3daa56..0000000000 --- a/doc/ocv.py +++ /dev/null @@ -1,1616 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - ocv domain, a modified copy of sphinx.domains.cpp + shpinx.domains.python. - The original copyright is below - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - The OpenCV C/C++/Python/Java/... language domain. - - :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import re -from copy import deepcopy - -from docutils import nodes -from docutils.parsers.rst import directives - -from sphinx import addnodes -from sphinx.roles import XRefRole -from sphinx.locale import l_, _ -from sphinx.domains import Domain, ObjType -from sphinx.directives import ObjectDescription -from sphinx.util.nodes import make_refnode -from sphinx.util.compat import Directive -from sphinx.util.docfields import Field, GroupedField, TypedField - -########################### Python Part ########################### - -# REs for Python signatures -py_sig_re = re.compile( - r'''^ ([\w.]*\.)? # class name(s) - (\w+) \s* # thing name - (?: \((.*)\) # optional: arguments - (?:\s* -> \s* (.*))? # return annotation - )? $ # and nothing more - ''', re.VERBOSE) - - -def _pseudo_parse_arglist(signode, arglist): - """"Parse" a list of arguments separated by commas. - - Arguments can have "optional" annotations given by enclosing them in - brackets. Currently, this will split at any comma, even if it's inside a - string literal (e.g. default argument value). - """ - paramlist = addnodes.desc_parameterlist() - stack = [paramlist] - try: - for argument in arglist.split(','): - argument = argument.strip() - ends_open = ends_close = 0 - while argument.startswith('['): - stack.append(addnodes.desc_optional()) - stack[-2] += stack[-1] - argument = argument[1:].strip() - while argument.startswith(']'): - stack.pop() - argument = argument[1:].strip() - while argument.endswith(']'): - ends_close += 1 - argument = argument[:-1].strip() - while argument.endswith('['): - ends_open += 1 - argument = argument[:-1].strip() - if argument: - stack[-1] += addnodes.desc_parameter(argument, argument, noemph=True) - while ends_open: - stack.append(addnodes.desc_optional()) - stack[-2] += stack[-1] - ends_open -= 1 - while ends_close: - stack.pop() - ends_close -= 1 - if len(stack) != 1: - raise IndexError - except IndexError: - # if there are too few or too many elements on the stack, just give up - # and treat the whole argument list as one argument, discarding the - # already partially populated paramlist node - signode += addnodes.desc_parameterlist() - signode[-1] += addnodes.desc_parameter(arglist, arglist) - else: - signode += paramlist - - -class OCVPyObject(ObjectDescription): - """ - Description of a general Python object. - """ - option_spec = { - 'noindex': directives.flag, - 'module': directives.unchanged, - } - - doc_field_types = [ - TypedField('parameter', label=l_('Parameters'), - names=('param', 'parameter', 'arg', 'argument', - 'keyword', 'kwarg', 'kwparam'), - typerolename='obj', typenames=('paramtype', 'type'), - can_collapse=True), - TypedField('variable', label=l_('Variables'), rolename='obj', - names=('var', 'ivar', 'cvar'), - typerolename='obj', typenames=('vartype',), - can_collapse=True), - GroupedField('exceptions', label=l_('Raises'), rolename='exc', - names=('raises', 'raise', 'exception', 'except'), - can_collapse=True), - Field('returnvalue', label=l_('Returns'), has_arg=False, - names=('returns', 'return')), - Field('returntype', label=l_('Return type'), has_arg=False, - names=('rtype',)), - ] - - def get_signature_prefix(self, sig): - """ - May return a prefix to put before the object name in the signature. - """ - return '' - - def needs_arglist(self): - """ - May return true if an empty argument list is to be generated even if - the document contains none. - """ - return False - - def handle_signature(self, sig, signode): - """ - Transform a Python signature into RST nodes. - Returns (fully qualified name of the thing, classname if any). - - If inside a class, the current class name is handled intelligently: - * it is stripped from the displayed name if present - * it is added to the full name (return value) if not present - """ - signode += nodes.strong("Python:", "Python:") - signode += addnodes.desc_name(" ", " ") - m = py_sig_re.match(sig) - if m is None: - raise ValueError - name_prefix, name, arglist, retann = m.groups() - - # determine module and class name (if applicable), as well as full name - modname = self.options.get( - 'module', self.env.temp_data.get('py:module')) - classname = self.env.temp_data.get('py:class') - if classname: - add_module = False - if name_prefix and name_prefix.startswith(classname): - fullname = name_prefix + name - # class name is given again in the signature - name_prefix = name_prefix[len(classname):].lstrip('.') - elif name_prefix: - # class name is given in the signature, but different - # (shouldn't happen) - fullname = classname + '.' + name_prefix + name - else: - # class name is not given in the signature - fullname = classname + '.' + name - else: - add_module = True - if name_prefix: - classname = name_prefix.rstrip('.') - fullname = name_prefix + name - else: - classname = '' - fullname = name - - signode['module'] = modname - signode['class'] = classname - signode['fullname'] = fullname - - sig_prefix = self.get_signature_prefix(sig) - if sig_prefix: - signode += addnodes.desc_annotation(sig_prefix, sig_prefix) - - if name_prefix: - signode += addnodes.desc_addname(name_prefix, name_prefix) - # exceptions are a special case, since they are documented in the - # 'exceptions' module. - elif add_module and self.env.config.add_module_names: - modname = self.options.get( - 'module', self.env.temp_data.get('py:module')) - if modname and modname != 'exceptions': - nodetext = modname + '.' - signode += addnodes.desc_addname(nodetext, nodetext) - - signode += addnodes.desc_name(name, name) - if not arglist: - if self.needs_arglist(): - # for callables, add an empty parameter list - signode += addnodes.desc_parameterlist() - if retann: - signode += addnodes.desc_returns(retann, retann) - return fullname, name_prefix - _pseudo_parse_arglist(signode, arglist) - if retann: - signode += addnodes.desc_returns(retann, retann) - return fullname, name_prefix - - def get_index_text(self, modname, name): - """ - Return the text for the index entry of the object. - """ - raise NotImplementedError('must be implemented in subclasses') - - def add_target_and_index(self, name_cls, sig, signode): - modname = self.options.get( - 'module', self.env.temp_data.get('py:module')) - fullname = (modname and modname + '.' or '') + name_cls[0] - # note target - if fullname not in self.state.document.ids: - signode['names'].append(fullname) - signode['ids'].append(fullname) - signode['first'] = (not self.names) - self.state.document.note_explicit_target(signode) - objects = self.env.domaindata['ocv']['objects'] - if fullname in objects: - self.env.warn( - self.env.docname, - 'duplicate object description of %s, ' % fullname + - 'other instance in ' + - self.env.doc2path(objects[fullname][0]) + - ', use :noindex: for one of them', - self.lineno) - objects.setdefault(fullname, (self.env.docname, self.objtype, name_cls[0])) - - indextext = self.get_index_text(modname, name_cls) - if indextext: - self.indexnode['entries'].append(('single', indextext, - fullname, fullname)) - - def before_content(self): - # needed for automatic qualification of members (reset in subclasses) - self.clsname_set = False - - def after_content(self): - if self.clsname_set: - self.env.temp_data['py:class'] = None - -class OCVPyModulelevel(OCVPyObject): - """ - Description of an object on module level (functions, data). - """ - directive_prefix = 'py' - - def needs_arglist(self): - return self.objtype == self.__class__.directive_prefix + 'function' - - def get_index_text(self, modname, name_cls): - if self.objtype == self.__class__.directive_prefix + 'function': - if not modname: - fname = name_cls[0] - if not fname.startswith("cv") and not fname.startswith("cv2"): - return _('%s() (Python function)') % fname - pos = fname.find(".") - modname = fname[:pos] - fname = fname[pos+1:] - return _('%s() (Python function in %s)') % (fname, modname) - return _('%s() (Python function in %s)') % (name_cls[0], modname) - elif self.objtype == 'pydata': - if not modname: - return _('%s (Python variable)') % name_cls[0] - return _('%s (in module %s)') % (name_cls[0], modname) - else: - return '' - -class OCVPyXRefRole(XRefRole): - def process_link(self, env, refnode, has_explicit_title, title, target): - refnode['ocv:module'] = env.temp_data.get('ocv:module') - refnode['ocv:class'] = env.temp_data.get('ocv:class') - if not has_explicit_title: - title = title.lstrip('.') # only has a meaning for the target - target = target.lstrip('~') # only has a meaning for the title - # if the first character is a tilde, don't display the module/class - # parts of the contents - if title[0:1] == '~': - title = title[1:] - dot = title.rfind('.') - if dot != -1: - title = title[dot+1:] - # if the first character is a dot, search more specific namespaces first - # else search builtins first - if target[0:1] == '.': - target = target[1:] - refnode['refspecific'] = True - return title, target - - -########################### C/C++/Java Part ########################### - -_identifier_re = re.compile(r'(~?\b[a-zA-Z_][a-zA-Z0-9_]*\b)') -_argument_name_re = re.compile(r'(~?\b[a-zA-Z_][a-zA-Z0-9_]*\b(?:\[\d*\])?|\.\.\.)') -_whitespace_re = re.compile(r'\s+(?u)') -_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'" - r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S) -_visibility_re = re.compile(r'\b(public|private|protected)\b') -_operator_re = re.compile(r'''(?x) - \[\s*\] - | \(\s*\) - | (<<|>>)=? - | \+\+ | -- | ->\*? - | [!<>=/*%+|&^-]=? - | ~ | && | \| | \|\| - | \, -''') - -_id_shortwords = { - 'char': 'c', - 'signed char': 'c', - 'unsigned char': 'C', - 'int': 'i', - 'signed int': 'i', - 'unsigned int': 'U', - 'long': 'l', - 'signed long': 'l', - 'unsigned long': 'L', - 'bool': 'b', - 'size_t': 's', - 'std::string': 'ss', - 'std::ostream': 'os', - 'std::istream': 'is', - 'std::iostream': 'ios', - 'std::vector': 'v', - 'std::map': 'm', - 'operator[]': 'subscript-operator', - 'operator()': 'call-operator', - 'operator!': 'not-operator', - 'operator<': 'lt-operator', - 'operator<=': 'lte-operator', - 'operator>': 'gt-operator', - 'operator>=': 'gte-operator', - 'operator=': 'assign-operator', - 'operator/': 'div-operator', - 'operator*': 'mul-operator', - 'operator%': 'mod-operator', - 'operator+': 'add-operator', - 'operator-': 'sub-operator', - 'operator|': 'or-operator', - 'operator&': 'and-operator', - 'operator^': 'xor-operator', - 'operator&&': 'sand-operator', - 'operator||': 'sor-operator', - 'operator==': 'eq-operator', - 'operator!=': 'neq-operator', - 'operator<<': 'lshift-operator', - 'operator>>': 'rshift-operator', - 'operator-=': 'sub-assign-operator', - 'operator+=': 'add-assign-operator', - 'operator*-': 'mul-assign-operator', - 'operator/=': 'div-assign-operator', - 'operator%=': 'mod-assign-operator', - 'operator&=': 'and-assign-operator', - 'operator|=': 'or-assign-operator', - 'operator<<=': 'lshift-assign-operator', - 'operator>>=': 'rshift-assign-operator', - 'operator^=': 'xor-assign-operator', - 'operator,': 'comma-operator', - 'operator->': 'pointer-operator', - 'operator->*': 'pointer-by-pointer-operator', - 'operator~': 'inv-operator', - 'operator++': 'inc-operator', - 'operator--': 'dec-operator', - 'operator new': 'new-operator', - 'operator new[]': 'new-array-operator', - 'operator delete': 'delete-operator', - 'operator delete[]': 'delete-array-operator' -} - - -class DefinitionError(Exception): - - def __init__(self, description): - self.description = description - - def __unicode__(self): - return self.description - - def __str__(self): - return unicode(self.encode('utf-8')) - - -class DefExpr(object): - - def __unicode__(self): - raise NotImplementedError() - - def __eq__(self, other): - if type(self) is not type(other): - return False - try: - for key, value in self.__dict__.iteritems(): - if value != getattr(other, value): - return False - except AttributeError: - return False - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def clone(self): - """Close a definition expression node""" - return deepcopy(self) - - def get_id(self): - """Returns the id for the node""" - return u'' - - def get_name(self): - """Returns the name. Returns either `None` or a node with - a name you might call :meth:`split_owner` on. - """ - return None - - def split_owner(self): - """Nodes returned by :meth:`get_name` can split off their - owning parent. This function returns the owner and the - name as a tuple of two items. If a node does not support - it, it returns None as owner and self as name. - """ - return None, self - - def prefix(self, prefix): - """Prefixes a name node (a node returned by :meth:`get_name`).""" - raise NotImplementedError() - - def __str__(self): - return unicode(self).encode('utf-8') - - def __repr__(self): - return '<%s %s>' % (self.__class__.__name__, self) - - -class PrimaryDefExpr(DefExpr): - - def get_name(self): - return self - - def prefix(self, prefix): - if isinstance(prefix, PathDefExpr): - prefix = prefix.clone() - prefix.path.append(self) - return prefix - return PathDefExpr([prefix, self]) - - -class NameDefExpr(PrimaryDefExpr): - - def __init__(self, name): - self.name = name - - def get_id(self): - name = _id_shortwords.get(self.name) - if name is not None: - return name - return self.name.replace(u' ', u'-') - - def __unicode__(self): - return unicode(self.name) - - -class PathDefExpr(PrimaryDefExpr): - - def __init__(self, parts): - self.path = parts - - def get_id(self): - rv = u'::'.join(x.get_id() for x in self.path) - return _id_shortwords.get(rv, rv) - - def split_owner(self): - if len(self.path) > 1: - return PathDefExpr(self.path[:-1]), self.path[-1] - return None, self - - def prefix(self, prefix): - if isinstance(prefix, PathDefExpr): - prefix = prefix.clone() - prefix.path.extend(self.path) - return prefix - return PathDefExpr([prefix] + self.path) - - def __unicode__(self): - return u'::'.join(map(unicode, self.path)) - - -class TemplateDefExpr(PrimaryDefExpr): - - def __init__(self, typename, args): - self.typename = typename - self.args = args - - def split_owner(self): - owner, typename = self.typename.split_owner() - return owner, TemplateDefExpr(typename, self.args) - - def get_id(self): - return u'%s:%s:' % (self.typename.get_id(), - u'.'.join(x.get_id() for x in self.args)) - - def __unicode__(self): - return u'%s<%s>' % (self.typename, u', '.join(map(unicode, self.args))) - - -class WrappingDefExpr(DefExpr): - - def __init__(self, typename): - self.typename = typename - - def get_name(self): - return self.typename.get_name() - - -class ModifierDefExpr(WrappingDefExpr): - - def __init__(self, typename, modifiers): - WrappingDefExpr.__init__(self, typename) - self.modifiers = modifiers - - def get_id(self): - pieces = [_id_shortwords.get(unicode(x), unicode(x)) - for x in self.modifiers] - pieces.append(self.typename.get_id()) - return u'-'.join(pieces) - - def __unicode__(self): - return u' '.join(map(unicode, list(self.modifiers) + [self.typename])) - - -class PtrDefExpr(WrappingDefExpr): - - def get_id(self): - return self.typename.get_id() + u'P' - - def __unicode__(self): - return u'%s*' % self.typename - - -class RefDefExpr(WrappingDefExpr): - - def get_id(self): - return self.typename.get_id() + u'R' - - def __unicode__(self): - return u'%s&' % self.typename - - -class ConstDefExpr(WrappingDefExpr): - - def __init__(self, typename, prefix=False): - WrappingDefExpr.__init__(self, typename) - self.prefix = prefix - - def get_id(self): - return self.typename.get_id() + u'C' - - def __unicode__(self): - return (self.prefix and u'const %s' or u'%s const') % self.typename - -class ConstTemplateDefExpr(WrappingDefExpr): - - def __init__(self, typename, prefix=False): - WrappingDefExpr.__init__(self, typename) - self.prefix = prefix - - def get_id(self): - return self.typename.get_id() + u'C' - - def __unicode__(self): - return (self.prefix and u'const %s' or u'%s const') % self.typename - - -class CastOpDefExpr(PrimaryDefExpr): - - def __init__(self, typename): - self.typename = typename - - def get_id(self): - return u'castto-%s-operator' % self.typename.get_id() - - def __unicode__(self): - return u'operator %s' % self.typename - - -class ArgumentDefExpr(DefExpr): - - def __init__(self, type, name, default=None): - self.name = name - self.type = type - self.default = default - - def get_name(self): - return self.name.get_name() - - def get_id(self): - if self.type is None: - return 'X' - return self.type.get_id() - - def __unicode__(self): - return (u'%s %s' % (self.type or u'', self.name or u'')).strip() + \ - (self.default is not None and u'=%s' % self.default or u'') - - -class NamedDefExpr(DefExpr): - - def __init__(self, name, visibility, static): - self.name = name - self.visibility = visibility - self.static = static - - def get_name(self): - return self.name.get_name() - - def get_modifiers(self): - rv = [] - if self.visibility != 'public': - rv.append(self.visibility) - if self.static: - rv.append(u'static') - return rv - - -class TypeObjDefExpr(NamedDefExpr): - - def __init__(self, name, visibility, static, typename): - NamedDefExpr.__init__(self, name, visibility, static) - self.typename = typename - - def get_id(self): - if self.typename is None: - return self.name.get_id() - return u'%s__%s' % (self.name.get_id(), self.typename.get_id()) - - def __unicode__(self): - buf = self.get_modifiers() - if self.typename is None: - buf.append(unicode(self.name)) - else: - buf.extend(map(unicode, (self.typename, self.name))) - return u' '.join(buf) - - -class MemberObjDefExpr(NamedDefExpr): - - def __init__(self, name, visibility, static, typename, value): - NamedDefExpr.__init__(self, name, visibility, static) - self.typename = typename - self.value = value - - def get_id(self): - return u'%s__%s' % (self.name.get_id(), self.typename.get_id()) - - def __unicode__(self): - buf = self.get_modifiers() - buf.append(u'%s %s' % (self.typename, self.name)) - if self.value is not None: - buf.append(u'= %s' % self.value) - return u' '.join(buf) - - -class FuncDefExpr(NamedDefExpr): - - def __init__(self, name, visibility, static, explicit, rv, - signature, const, pure_virtual, virtual): - NamedDefExpr.__init__(self, name, visibility, static) - self.rv = rv - self.signature = signature - self.explicit = explicit - self.const = const - self.pure_virtual = pure_virtual - self.virtual = virtual - - def get_id(self): - return u'%s%s%s' % ( - self.name.get_id(), - self.signature and u'__' + - u'.'.join(x.get_id() for x in self.signature) or u'', - self.const and u'C' or u'' - ) - - def __unicode__(self): - buf = self.get_modifiers() - if self.explicit: - buf.append(u'explicit') - if self.virtual: - buf.append(u'virtual') - if self.rv is not None: - buf.append(unicode(self.rv)) - buf.append(u'%s(%s)' % (self.name, u', '.join( - map(unicode, self.signature)))) - if self.const: - buf.append(u'const') - if self.pure_virtual: - buf.append(u'= 0') - return u' '.join(buf) - - -class ClassDefExpr(NamedDefExpr): - - def __init__(self, name, visibility, static, parents = None): - NamedDefExpr.__init__(self, name, visibility, static) - self.parents = parents - - def get_id(self): - return self.name.get_id() - - def __unicode__(self): - buf = self.get_modifiers() - buf.append(unicode(self.name)) - return u' '.join(buf) - - -class DefinitionParser(object): - - # mapping of valid type modifiers. if the set is None it means - # the modifier can prefix all types, otherwise only the types - # (actually more keywords) in the set. Also check - # _guess_typename when changing this. - _modifiers = { - 'volatile': None, - 'register': None, - 'mutable': None, - 'const': None, - 'typename': None, - 'unsigned': set(('char', 'short', 'int', 'long')), - 'signed': set(('char', 'short', 'int', 'long')), - 'short': set(('int',)), - 'long': set(('int', 'long', 'double')) - } - - def __init__(self, definition): - self.definition = definition.strip() - self.pos = 0 - self.end = len(self.definition) - self.last_match = None - self._previous_state = (0, None) - - def fail(self, msg): - raise DefinitionError('Invalid definition: %s [error at %d]\n %s' % - (msg, self.pos, self.definition)) - - def match(self, regex): - match = regex.match(self.definition, self.pos) - if match is not None: - self._previous_state = (self.pos, self.last_match) - self.pos = match.end() - self.last_match = match - return True - return False - - def backout(self): - self.pos, self.last_match = self._previous_state - - def skip_string(self, string): - strlen = len(string) - if self.definition[self.pos:self.pos + strlen] == string: - self.pos += strlen - return True - return False - - def skip_word(self, word): - return self.match(re.compile(r'\b%s\b' % re.escape(word))) - - def skip_ws(self): - return self.match(_whitespace_re) - - @property - def eof(self): - return self.pos >= self.end - - @property - def current_char(self): - try: - return self.definition[self.pos] - except IndexError: - return 'EOF' - - @property - def matched_text(self): - if self.last_match is not None: - return self.last_match.group() - - def _parse_operator(self): - self.skip_ws() - # thank god, a regular operator definition - if self.match(_operator_re): - return NameDefExpr('operator' + - _whitespace_re.sub('', self.matched_text)) - # new/delete operator? - for allocop in 'new', 'delete': - if not self.skip_word(allocop): - continue - self.skip_ws() - if self.skip_string('['): - self.skip_ws() - if not self.skip_string(']'): - self.fail('expected "]" for ' + allocop) - allocop += '[]' - return NameDefExpr('operator ' + allocop) - - # oh well, looks like a cast operator definition. - # In that case, eat another type. - type = self._parse_type() - return CastOpDefExpr(type) - - def _parse_name(self): - if not self.match(_argument_name_re): - self.fail('expected name') - identifier = self.matched_text - - # strictly speaking, operators are not regular identifiers - # but because operator is a keyword, it might not be used - # for variable names anyways, so we can safely parse the - # operator here as identifier - if identifier == 'operator': - return self._parse_operator() - - return NameDefExpr(identifier) - - def _guess_typename(self, path): - if not path: - return [], 'int' - # for the long type, we don't want the int in there - if 'long' in path: - path = [x for x in path if x != 'int'] - # remove one long - path.remove('long') - return path, 'long' - if path[-1] in ('int', 'char'): - return path[:-1], path[-1] - return path, 'int' - - def _attach_crefptr(self, expr, is_const=False): - if is_const: - expr = ConstDefExpr(expr, prefix=True) - while 1: - self.skip_ws() - if self.skip_word('const'): - expr = ConstDefExpr(expr) - elif self.skip_string('*'): - expr = PtrDefExpr(expr) - elif self.skip_string('&'): - expr = RefDefExpr(expr) - else: - return expr - - def _peek_const(self, path): - try: - path.remove('const') - return True - except ValueError: - return False - - def _parse_builtin(self, modifier): - path = [modifier] - following = self._modifiers[modifier] - while 1: - self.skip_ws() - if not self.match(_identifier_re): - break - identifier = self.matched_text - if identifier in following: - path.append(identifier) - following = self._modifiers[modifier] - assert following - else: - self.backout() - break - - is_const = self._peek_const(path) - modifiers, typename = self._guess_typename(path) - rv = ModifierDefExpr(NameDefExpr(typename), modifiers) - return self._attach_crefptr(rv, is_const) - - def _parse_type_expr(self): - typename = self._parse_name() - if typename and self.skip_string('['): - typename.name += '[' - if self.match(re.compile(r'\d*')): - typename.name += self.last_match.group(0) - typename.name += ']' - if not self.skip_string(']'): - self.fail('expected type') - self.skip_ws() - if not self.skip_string('<'): - return typename - - args = [] - while 1: - self.skip_ws() - if self.skip_string('>'): - break - if args: - if not self.skip_string(','): - self.fail('"," or ">" in template expected') - self.skip_ws() - args.append(self._parse_type(True)) - return TemplateDefExpr(typename, args) - - def _parse_type(self, in_template=False): - self.skip_ws() - result = [] - modifiers = [] - - if self.match(re.compile(r'template\w*<([^>]*)>')): - args = self.last_match.group(1).split(',') - args = [a.strip() for a in args] - modifiers.append(TemplateDefExpr('template', args)) - - # if there is a leading :: or not, we don't care because we - # treat them exactly the same. Buf *if* there is one, we - # don't have to check for type modifiers - if not self.skip_string('::'): - self.skip_ws() - while self.match(_identifier_re): - modifier = self.matched_text - if modifier in self._modifiers: - following = self._modifiers[modifier] - # if the set is not none, there is a limited set - # of types that might follow. It is technically - # impossible for a template to follow, so what - # we do is go to a different function that just - # eats types - if following is not None: - return self._parse_builtin(modifier) - modifiers.append(modifier) - else: - self.backout() - break - - while 1: - self.skip_ws() - if (in_template and self.current_char in ',>') or \ - (result and not self.skip_string('::')) or \ - self.eof: - break - result.append(self._parse_type_expr()) - - if not result: - self.fail('expected type') - if len(result) == 1: - rv = result[0] - else: - rv = PathDefExpr(result) - is_const = self._peek_const(modifiers) - if is_const: - rv = ConstDefExpr(rv, prefix=True) - if modifiers: - rv = ModifierDefExpr(rv, modifiers) - return self._attach_crefptr(rv, False) - - def _parse_default_expr(self): - self.skip_ws() - if self.match(_string_re): - return self.matched_text - paren_stack_depth = 0 - max_pos = len(self.definition) - rv_start = self.pos - while 1: - idx0 = self.definition.find('(', self.pos) - idx1 = self.definition.find(',', self.pos) - idx2 = self.definition.find(')', self.pos) - if idx0 < 0: - idx0 = max_pos - if idx1 < 0: - idx1 = max_pos - if idx2 < 0: - idx2 = max_pos - idx = min(idx0, idx1, idx2) - if idx >= max_pos: - self.fail('unexpected end in default expression') - if idx == idx0: - paren_stack_depth += 1 - elif idx == idx2: - paren_stack_depth -= 1 - if paren_stack_depth < 0: - break - elif paren_stack_depth == 0: - break - self.pos = idx+1 - - rv = self.definition[rv_start:idx] - self.pos = idx - return rv - - def _parse_signature(self): - if r'CvStatModel::train' in self.definition: - # hack to skip parsing of problematic definition - self.pos = self.end - return [ArgumentDefExpr("const Mat&", "train_data", None), ArgumentDefExpr(None, self.definition[self.definition.find("["):-1], None)], False, True - - self.skip_ws() - if not self.skip_string('('): - self.fail('expected parentheses for function') - - args = [] - while 1: - self.skip_ws() - if self.eof: - self.fail('missing closing parentheses') - if self.skip_string(')'): - break - if args: - if not self.skip_string(','): - self.fail('expected comma between arguments') - self.skip_ws() - - argtype = self._parse_type() - self.skip_ws() - if unicode(argtype) == u"...": - if not self.skip_string(')'): - self.fail("var arg must be the last argument") - args.append(ArgumentDefExpr(None, argtype, None)) - break - argname = default = None - if self.skip_string('='): - self.pos += 1 - default = self._parse_default_expr() - elif self.current_char not in ',)': - argname = self._parse_name() - self.skip_ws() - if self.skip_string('='): - default = self._parse_default_expr() - - args.append(ArgumentDefExpr(argtype, argname, default)) - self.skip_ws() - const = self.skip_word('const') - if const: - self.skip_ws() - if self.skip_string('='): - self.skip_ws() - if not (self.skip_string('0') or \ - self.skip_word('NULL') or \ - self.skip_word('nullptr')): - self.fail('pure virtual functions must be defined with ' - 'either 0, NULL or nullptr, other macros are ' - 'not allowed') - pure_virtual = True - else: - pure_virtual = False - return args, const, pure_virtual - - def _parse_visibility_static(self): - visibility = 'public' - if self.match(_visibility_re): - visibility = self.matched_text - static = self.skip_word('static') - return visibility, static - - def parse_type(self): - return self._parse_type() - - def parse_type_object(self): - visibility, static = self._parse_visibility_static() - typename = self._parse_type() - self.skip_ws() - if not self.eof: - name = self._parse_type() - else: - name = typename - typename = None - return TypeObjDefExpr(name, visibility, static, typename) - - def parse_member_object(self): - visibility, static = self._parse_visibility_static() - typename = self._parse_type() - name = self._parse_type() - self.skip_ws() - if self.skip_string('='): - value = self.read_rest().strip() - else: - value = None - return MemberObjDefExpr(name, visibility, static, typename, value) - - def parse_enum_member_object(self): - visibility, static = self._parse_visibility_static() - typename = None - name = self._parse_type() - self.skip_ws() - if self.skip_string('='): - value = self.read_rest().strip() - else: - value = None - return MemberObjDefExpr(name, visibility, static, typename, value) - - def parse_function(self): - visibility, static = self._parse_visibility_static() - if self.skip_word('explicit'): - explicit = True - self.skip_ws() - else: - explicit = False - if self.skip_word('virtual'): - virtual = True - self.skip_ws() - else: - virtual = False - rv = self._parse_type() - self.skip_ws() - # some things just don't have return values - if self.current_char == '(': - name = rv - rv = None - else: - name = self._parse_type() - return FuncDefExpr(name, visibility, static, explicit, rv, - *self._parse_signature(), virtual = virtual) - - def parse_class(self): - visibility, static = self._parse_visibility_static() - typename = self._parse_type() - parent = None - self.skip_ws() - parents = [] - if self.skip_string(':'): - while not self.eof: - self.skip_ws() - classname_pos = self.pos - pvisibility, pstatic = self._parse_visibility_static() - if pstatic: - self.fail('unsepected static keyword, got %r' % - self.definition[self.classname_pos:]) - parents.append(ClassDefExpr(self._parse_type(), pvisibility, pstatic)) - if not self.skip_string(','): - break - return ClassDefExpr(typename, visibility, static, parents) - - def read_rest(self): - rv = self.definition[self.pos:] - self.pos = self.end - return rv - - def assert_end(self): - self.skip_ws() - if not self.eof: - self.fail('expected end of definition, got %r' % - self.definition[self.pos:]) - - -class OCVObject(ObjectDescription): - """Description of a C++ language object.""" - - langname = "C++" - ismember = False - - doc_field_types = [ - TypedField('parameter', label=l_('Parameters'), - names=('param', 'parameter', 'arg', 'argument'), - typerolename='type', typenames=('type',)), - Field('returnvalue', label=l_('Returns'), has_arg=False, - names=('returns', 'return')), - Field('returntype', label=l_('Return type'), has_arg=False, - names=('rtype',)), - ] - - def attach_name(self, node, name): - owner, name = name.split_owner() - varname = unicode(name) - if owner is not None: - owner = unicode(owner) + '::' - node += addnodes.desc_addname(owner, owner) - node += addnodes.desc_name(varname, varname) - - def attach_type(self, node, type): - # XXX: link to c? - text = unicode(type) - pnode = addnodes.pending_xref( - '', refdomain='ocv', reftype='type', - reftarget=text, modname=None, classname=None) - pnode['ocv:parent'] = self.env.temp_data.get('ocv:parent') - pnode += nodes.Text(text) - node += pnode - - def attach_modifiers(self, node, obj): - if not self.__class__.ismember: - lname = self.__class__.langname - node += nodes.strong(lname + ":", lname + ":") - node += addnodes.desc_name(" ", " ") - - if obj.visibility != 'public': - node += addnodes.desc_annotation(obj.visibility, - obj.visibility) - node += nodes.Text(' ') - if obj.static: - node += addnodes.desc_annotation('static', 'static') - node += nodes.Text(' ') - - def add_target_and_index(self, sigobj, sig, signode): - theid = sig#obj.get_id() - theid = re.sub(r" +", " ", theid) - if self.objtype == 'emember': - theid = re.sub(r" ?=.*", "", theid) - theid = re.sub(r"=[^,()]+\([^)]*?\)[^,)]*(,|\))", "\\1", theid) - theid = re.sub(r"=\w*[^,)(]+(,|\))", "\\1", theid) - theid = theid.replace("( ", "(").replace(" )", ")") - name = unicode(sigobj.name) - if theid not in self.state.document.ids: - signode['names'].append(theid) - signode['ids'].append(theid) - signode['first'] = (not self.names) - self.state.document.note_explicit_target(signode) - - #self.env.domaindata['ocv']['objects'].setdefault(name, - #(self.env.docname, self.objtype, theid)) - self.env.domaindata['ocv']['objects'].setdefault(theid, - (self.env.docname, self.objtype, theid)) - self.env.domaindata['ocv']['objects2'].setdefault(name, - (self.env.docname, self.objtype, theid)) - - indextext = self.get_index_text(name) - if indextext: - self.indexnode['entries'].append(('single', indextext, theid, name)) - - def before_content(self): - lastname = self.names and self.names[-1] - if lastname and not self.env.temp_data.get('ocv:parent'): - assert isinstance(lastname, NamedDefExpr) - self.env.temp_data['ocv:parent'] = lastname.name - self.parentname_set = True - else: - self.parentname_set = False - - def after_content(self): - if self.parentname_set: - self.env.temp_data['ocv:parent'] = None - - def parse_definition(self, parser): - raise NotImplementedError() - - def describe_signature(self, signode, arg): - raise NotImplementedError() - - def handle_signature(self, sig, signode): - parser = DefinitionParser(sig) - try: - rv = self.parse_definition(parser) - parser.assert_end() - except DefinitionError, e: - self.env.warn(self.env.docname, - e.description, self.lineno) - raise ValueError - self.describe_signature(signode, rv) - - parent = self.env.temp_data.get('ocv:parent') - if parent is not None: - rv = rv.clone() - rv.name = rv.name.prefix(parent) - return rv - - -class OCVClassObject(OCVObject): - object_annotation = "class " - object_long_name = "class" - - def attach_modifiers(self, node, obj, skip_visibility = 'public'): - if obj.visibility != skip_visibility: - node += addnodes.desc_annotation(obj.visibility, - obj.visibility) - node += nodes.Text(' ') - if obj.static: - node += addnodes.desc_annotation('static', 'static') - node += nodes.Text(' ') - - def get_index_text(self, name): - return _('%s (C++ %s)') % (name, self.__class__.object_long_name) - - def parse_definition(self, parser): - return parser.parse_class() - - def describe_signature(self, signode, cls): - self.attach_modifiers(signode, cls) - signode += addnodes.desc_annotation(self.__class__.object_annotation, self.__class__.object_annotation) - self.attach_name(signode, cls.name) - first_parent = True - for p in cls.parents: - if first_parent: - signode += nodes.Text(' : ') - first_parent = False - else: - signode += nodes.Text(', ') - self.attach_modifiers(signode, p, None) - self.attach_name(signode, p.name) - -class OCVStructObject(OCVClassObject): - object_annotation = "struct " - object_long_name = "structure" - -class OCVTypeObject(OCVObject): - - def get_index_text(self, name): - if self.objtype == 'type': - return _('%s (C++ type)') % name - return '' - - def parse_definition(self, parser): - return parser.parse_type_object() - - def describe_signature(self, signode, obj): - self.attach_modifiers(signode, obj) - signode += addnodes.desc_annotation('type ', 'type ') - if obj.typename is not None: - self.attach_type(signode, obj.typename) - signode += nodes.Text(' ') - self.attach_name(signode, obj.name) - -class OCVEnumObject(OCVObject): - - def get_index_text(self, name): - if self.objtype == 'enum': - return _('%s (enum)') % name - return '' - - def parse_definition(self, parser): - return parser.parse_type_object() - - def describe_signature(self, signode, obj): - self.attach_modifiers(signode, obj) - signode += addnodes.desc_annotation('enum ', 'enum ') - if obj.typename is not None: - self.attach_type(signode, obj.typename) - signode += nodes.Text(' ') - self.attach_name(signode, obj.name) - - -class OCVMemberObject(OCVObject): - ismember = True - - def get_index_text(self, name): - if self.objtype == 'member': - return _('%s (C++ member)') % name - return '' - - def parse_definition(self, parser): - parent_class = self.env.temp_data.get('ocv:parent') - if parent_class is None: - parser.fail("missing parent structure/class") - return parser.parse_member_object() - - def describe_signature(self, signode, obj): - self.attach_modifiers(signode, obj) - if obj.typename: - self.attach_type(signode, obj.typename) - signode += nodes.Text(' ') - self.attach_name(signode, obj.name) - if obj.value is not None: - signode += nodes.Text(u' = ' + obj.value) - -class OCVEnumMemberObject(OCVMemberObject): - def parse_definition(self, parser): - # parent_class = self.env.temp_data.get('ocv:parent') - # if parent_class is None: - # parser.fail("missing parent structure/class") - return parser.parse_enum_member_object() - -class OCVFunctionObject(OCVObject): - - def attach_function(self, node, func): - owner, name = func.name.split_owner() - if owner is not None: - owner = unicode(owner) + '::' - node += addnodes.desc_addname(owner, owner) - - # cast operator is special. in this case the return value - # is reversed. - if isinstance(name, CastOpDefExpr): - node += addnodes.desc_name('operator', 'operator') - node += nodes.Text(u' ') - self.attach_type(node, name.typename) - else: - funcname = unicode(name) - node += addnodes.desc_name(funcname, funcname) - - paramlist = addnodes.desc_parameterlist() - for arg in func.signature: - param = addnodes.desc_parameter('', '', noemph=True) - if arg.type is not None: - self.attach_type(param, arg.type) - param += nodes.Text(u' ') - #param += nodes.emphasis(unicode(arg.name), unicode(arg.name)) - sbrIdx = unicode(arg.name).find("[") - if sbrIdx < 0: - param += nodes.strong(unicode(arg.name), unicode(arg.name)) - else: - param += nodes.strong(unicode(arg.name)[:sbrIdx], unicode(arg.name)[:sbrIdx]) - param += nodes.Text(unicode(arg.name)[sbrIdx:]) - if arg.default is not None: - def_ = u'=' + unicode(arg.default) - #param += nodes.emphasis(def_, def_) - param += nodes.Text(def_) - paramlist += param - - node += paramlist - if func.const: - node += addnodes.desc_addname(' const', ' const') - if func.pure_virtual: - node += addnodes.desc_addname(' = 0', ' = 0') - - def get_index_text(self, name): - lname = self.__class__.langname - if lname == "C" and name.startswith("cv"): - name = name[2:] - return _('%s (%s function)') % (name, lname) - - def parse_definition(self, parser): - return parser.parse_function() - - def describe_signature(self, signode, func): - self.attach_modifiers(signode, func) - if func.explicit: - signode += addnodes.desc_annotation('explicit', 'explicit') - signode += nodes.Text(' ') - if func.virtual: - signode += addnodes.desc_annotation('virtual', 'virtual') - signode += nodes.Text(' ') - # return value is None for things with a reverse return value - # such as casting operator definitions or constructors - # and destructors. - if func.rv is not None: - self.attach_type(signode, func.rv) - signode += nodes.Text(u' ') - self.attach_function(signode, func) - - -class OCVCurrentNamespace(Directive): - """This directive is just to tell Sphinx that we're documenting - stuff in namespace foo. - """ - - has_content = False - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = True - option_spec = {} - - def run(self): - env = self.state.document.settings.env - if self.arguments[0].strip() in ('NULL', '0', 'nullptr'): - env.temp_data['ocv:prefix'] = None - else: - parser = DefinitionParser(self.arguments[0]) - try: - prefix = parser.parse_type() - parser.assert_end() - except DefinitionError, e: - self.env.warn(self.env.docname, - e.description, self.lineno) - else: - env.temp_data['ocv:prefix'] = prefix - return [] - - -class OCVXRefRole(XRefRole): - - def process_link(self, env, refnode, has_explicit_title, title, target): - refnode['ocv:parent'] = env.temp_data.get('ocv:parent') - if not has_explicit_title: - target = target.lstrip('~') # only has a meaning for the title - # if the first character is a tilde, don't display the module/class - # parts of the contents - if title[:1] == '~': - title = title[1:] - dcolon = title.rfind('::') - if dcolon != -1: - title = title[dcolon + 2:] - return title, target - - -class OCVCFunctionObject(OCVFunctionObject): - langname = "C" - -class OCVJavaFunctionObject(OCVFunctionObject): - langname = "Java" - - -class OCVDomain(Domain): - """OpenCV C++ language domain.""" - name = 'ocv' - label = 'C++' - object_types = { - 'class': ObjType(l_('class'), 'class'), - 'struct': ObjType(l_('struct'), 'struct'), - 'function': ObjType(l_('function'), 'func', 'funcx'), - 'cfunction': ObjType(l_('cfunction'), 'cfunc', 'cfuncx'), - 'jfunction': ObjType(l_('jfunction'), 'jfunc', 'jfuncx'), - 'pyfunction': ObjType(l_('pyfunction'), 'pyfunc'), - 'member': ObjType(l_('member'), 'member'), - 'emember': ObjType(l_('emember'), 'emember'), - 'type': ObjType(l_('type'), 'type'), - 'enum': ObjType(l_('enum'), 'enum') - } - - directives = { - 'class': OCVClassObject, - 'struct': OCVStructObject, - 'function': OCVFunctionObject, - 'cfunction': OCVCFunctionObject, - 'jfunction': OCVJavaFunctionObject, - 'pyfunction': OCVPyModulelevel, - 'member': OCVMemberObject, - 'emember': OCVEnumMemberObject, - 'type': OCVTypeObject, - 'enum': OCVEnumObject, - 'namespace': OCVCurrentNamespace - } - roles = { - 'class': OCVXRefRole(), - 'struct': OCVXRefRole(), - 'func' : OCVXRefRole(fix_parens=True), - 'funcx' : OCVXRefRole(), - 'cfunc' : OCVXRefRole(fix_parens=True), - 'cfuncx' : OCVXRefRole(), - 'jfunc' : OCVXRefRole(fix_parens=True), - 'jfuncx' : OCVXRefRole(), - 'pyfunc' : OCVPyXRefRole(), - 'member': OCVXRefRole(), - 'emember': OCVXRefRole(), - 'type': OCVXRefRole(), - 'enum': OCVXRefRole() - } - initial_data = { - 'objects': {}, # fullname -> docname, objtype - } - - def __init__(self, env): - Domain.__init__(self, env) - self.data['objects2'] = {} - - def clear_doc(self, docname): - for fullname, (fn, _, _) in self.data['objects'].items(): - if fn == docname: - del self.data['objects'][fullname] - - def resolve_xref(self, env, fromdocname, builder, - typ, target, node, contnode): - def _create_refnode(expr): - name = unicode(expr) - if "type" in self.objtypes_for_role(typ): - return None - if "cfunction" in self.objtypes_for_role(typ): - if not name.startswith(u'cv'): - name = u'cv' + name - dict = self.data['objects'] - if name not in dict: - dict = self.data['objects2'] - if name not in dict: - refdoc = node.get('refdoc', fromdocname) - env.warn(refdoc, 'unresolved reference: %r - %r' % (target, typ), node.line) - return None - obj = dict[name] - if obj[1] not in self.objtypes_for_role(typ): - return None - title = obj[2] - if "class" in self.objtypes_for_role(typ): - title = u"class " + title - elif "struct" in self.objtypes_for_role(typ): - title = u"struct " + title - return make_refnode(builder, fromdocname, obj[0], obj[2], - contnode, title) - - parser = DefinitionParser(target) - try: - expr = parser.parse_type().get_name() - parser.skip_ws() - if not parser.eof or expr is None: - raise DefinitionError('') - except DefinitionError: - refdoc = node.get('refdoc', fromdocname) - env.warn(refdoc, 'unparseable C++ definition: %r' % target, - node.line) - return None - - parent = node['ocv:parent'] - - rv = _create_refnode(expr) - if rv is not None or parent is None: - return rv - parent = parent.get_name() - - rv = _create_refnode(expr.prefix(parent)) - if rv is not None: - return rv - - parent, name = parent.split_owner() - return _create_refnode(expr.prefix(parent)) - - def get_objects(self): - for refname, (docname, type, theid) in self.data['objects'].iteritems(): - yield (refname, refname, type, docname, refname, 1) - - def get_type_name(self, type, primary=False): - """ - Return full name for given ObjType. - """ - if primary: - return type.lname - - return { - 'class': _('C++ class'), - 'struct': _('C/C++ struct'), - 'function': _('C++ function'), - 'cfunction': _('C function'), - 'jfunction': _('Java method'), - 'pyfunction': _('Python function'), - 'member': _('C++ member'), - 'emember': _('enum member'), - 'type': _('C/C++ type'), - 'enum': _('C/C++ enum'), - 'namespace': _('C++ namespace'), - }.get(type.lname, _('%s %s') % (self.label, type.lname)) - -def setup(app): - app.add_domain(OCVDomain) diff --git a/doc/opencv_cheatsheet.tex b/doc/opencv_cheatsheet.tex deleted file mode 100644 index 01d5c275d9..0000000000 --- a/doc/opencv_cheatsheet.tex +++ /dev/null @@ -1,620 +0,0 @@ -% -% The OpenCV cheatsheet structure: -% -% opencv data structures -% point, rect -% matrix -% -% creating matrices -% from scratch -% from previously allocated data: plain arrays, vectors -% converting to/from old-style structures -% -% element access, iteration through matrix elements -% -% copying & shuffling matrix data -% copying & converting the whole matrices -% extracting matrix parts & copying them -% split, merge & mixchannels -% flip, transpose, repeat -% -% matrix & image operations: -% arithmetics & logic -% matrix multiplication, inversion, determinant, trace, SVD -% statistical functions -% -% basic image processing: -% image filtering with predefined & custom filters -% example: finding local maxima -% geometrical transformations, resize, warpaffine, perspective & remap. -% color space transformations -% histograms & back projections -% contours -% -% i/o: -% displaying images -% saving/loading to/from file (XML/YAML & image file formats) -% reading videos & camera feed, writing videos -% -% operations on point sets: -% findcontours, bounding box, convex hull, min area rect, -% transformations, to/from homogeneous coordinates -% matching point sets: homography, fundamental matrix, rigid transforms -% -% 3d: -% camera calibration, pose estimation. -% uncalibrated case -% stereo: rectification, running stereo correspondence, obtaining the depth. -% -% feature detection: -% features2d toolbox -% -% object detection: -% using a classifier running on a sliding window: cascadeclassifier + hog. -% using salient point features: features2d -> matching -% -% statistical data processing: -% clustering (k-means), -% classification + regression (SVM, boosting, k-nearest), -% compressing data (PCA) -% - -\documentclass[10pt,landscape]{article} -\usepackage[usenames,dvips,pdftex]{color} -\usepackage{multicol} -\usepackage{calc} -\usepackage{ifthen} -\usepackage[pdftex]{color,graphicx} -\usepackage[landscape]{geometry} -\usepackage{hyperref} -\usepackage[T1]{fontenc} -\hypersetup{colorlinks=true, filecolor=black, linkcolor=black, urlcolor=blue, citecolor=black} -\graphicspath{{./images/}} - -% This sets page margins to .5 inch if using letter paper, and to 1cm -% if using A4 paper. (This probably isn't strictly necessary.) -% If using another size paper, use default 1cm margins. -\ifthenelse{\lengthtest { \paperwidth = 11in}} - { \geometry{top=.5in,left=.5in,right=.5in,bottom=.5in} } - {\ifthenelse{ \lengthtest{ \paperwidth = 297mm}} - {\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} } - {\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} } - } - -% Turn off header and footer -% \pagestyle{empty} - -% Redefine section commands to use less space -\makeatletter -\renewcommand{\section}{\@startsection{section}{1}{0mm}% - {-1ex plus -.5ex minus -.2ex}% - {0.5ex plus .2ex}%x - {\normalfont\large\bfseries}} -\renewcommand{\subsection}{\@startsection{subsection}{2}{0mm}% - {-1explus -.5ex minus -.2ex}% - {0.5ex plus .2ex}% - {\normalfont\normalsize\bfseries}} -\renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{0mm}% - {-1ex plus -.5ex minus -.2ex}% - {1ex plus .2ex}% - {\normalfont\small\bfseries}} -\makeatother - -% Define BibTeX command -\def\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em - T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} - -% Don't print section numbers -\setcounter{secnumdepth}{0} - - -%\setlength{\parindent}{0pt} -%\setlength{\parskip}{0pt plus 0.5ex} - -\newcommand{\ccode}[1]{ -\begin{alltt} -#1 -\end{alltt} -} - -% ----------------------------------------------------------------------- - -\begin{document} - -\raggedright -\footnotesize -\begin{multicols}{3} - - -% multicol parameters -% These lengths are set only within the two main columns -%\setlength{\columnseprule}{0.25pt} -\setlength{\premulticols}{1pt} -\setlength{\postmulticols}{1pt} -\setlength{\multicolsep}{1pt} -\setlength{\columnsep}{2pt} - -\begin{center} - \Large{\textbf{OpenCV 2.4 Cheat Sheet (C++)}} \\ -\end{center} -\newlength{\MyLen} -\settowidth{\MyLen}{\texttt{letterpaper}/\texttt{a4paper} \ } - -%\section{Filesystem Concepts} -%\begin{tabular}{@{}p{\the\MyLen}% - % @{}p{\linewidth-\the\MyLen}@{}} -%\texttt{\href{http://www.ros.org/wiki/Packages}{package}} & The lowest level of ROS software organization. \\ -%\texttt{\href{http://www.ros.org/wiki/Manifest}{manifest}} & Description of a ROS package. \\ -%\texttt{\href{http://www.ros.org/wiki/Stack}{stack}} & Collections of ROS packages that form a higher-level library. \\ -%\texttt{\href{http://www.ros.org/wiki/Stack Manifest}{stack manifest}} & Description of a ROS stack. -%\end{tabular} - -\emph{The OpenCV C++ reference manual is here: \url{http://docs.opencv.org}. Use \textbf{Quick Search} to find descriptions of the particular functions and classes} - -\section{Key OpenCV Classes} -\begin{tabular}{@{}p{\the\MyLen}% - @{}p{\linewidth-\the\MyLen}@{}} -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Point_}{Point\_}} & Template 2D point class \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Point3_}{Point3\_}} & Template 3D point class \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Size_}{Size\_}} & Template size (width, height) class \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Vec}{Vec}} & Template short vector class \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Matx}{Matx}} & Template small matrix class \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Scalar_}{Scalar}} & 4-element vector \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Rect_}{Rect}} & Rectangle \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Range}{Range}} & Integer value range \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Mat}{Mat}} & 2D or multi-dimensional dense array (can be used to store matrices, images, histograms, feature descriptors, voxel volumes etc.)\\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#sparsemat}{SparseMat}} & Multi-dimensional sparse array \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Ptr}{Ptr}} & Template smart pointer class -\end{tabular} - -\section{Matrix Basics} -\begin{tabbing} - -\textbf{Cr}\=\textbf{ea}\=\textbf{te}\={} \textbf{a matrix} \\ -\> \texttt{Mat image(240, 320, CV\_8UC3);} \\ - -\textbf{[Re]allocate a pre-declared matrix}\\ -\> \texttt{image.\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#mat-create}{create}(480, 640, CV\_8UC3);}\\ - -\textbf{Create a matrix initialized with a constant}\\ -\> \texttt{Mat A33(3, 3, CV\_32F, Scalar(5));} \\ -\> \texttt{Mat B33(3, 3, CV\_32F); B33 = Scalar(5);} \\ -\> \texttt{Mat C33 = Mat::ones(3, 3, CV\_32F)*5.;} \\ -\> \texttt{Mat D33 = Mat::zeros(3, 3, CV\_32F) + 5.;} \\ - -\textbf{Create a matrix initialized with specified values}\\ -\> \texttt{double a = CV\_PI/3;} \\ -\> \texttt{Mat A22 = (Mat\_(2, 2) <<} \\ -\> \> \texttt{cos(a), -sin(a), sin(a), cos(a));} \\ -\> \texttt{float B22data[] = \{cos(a), -sin(a), sin(a), cos(a)\};} \\ -\> \texttt{Mat B22 = Mat(2, 2, CV\_32F, B22data).clone();}\\ - -\textbf{Initialize a random matrix}\\ -\> \texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#randu}{randu}(image, Scalar(0), Scalar(256)); }\textit{// uniform dist}\\ -\> \texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#randn}{randn}(image, Scalar(128), Scalar(10)); }\textit{// Gaussian dist}\\ - -\textbf{Convert matrix to/from other structures}\\ -\>\textbf{(without copying the data)}\\ -\> \texttt{Mat image\_alias = image;}\\ -\> \texttt{float* Idata=new float[480*640*3];}\\ -\> \texttt{Mat I(480, 640, CV\_32FC3, Idata);}\\ -\> \texttt{vector iptvec(10);}\\ -\> \texttt{Mat iP(iptvec); }\textit{// iP -- 10x1 CV\_32SC2 matrix}\\ -\> \texttt{IplImage* oldC0 = cvCreateImage(cvSize(320,240),16,1);}\\ -\> \texttt{Mat newC = cvarrToMat(oldC0);}\\ -\> \texttt{IplImage oldC1 = newC; CvMat oldC2 = newC;}\\ - -\textbf{... (with copying the data)}\\ -\> \texttt{Mat newC2 = cvarrToMat(oldC0).clone();}\\ -\> \texttt{vector ptvec = Mat\_(iP);}\\ - -\>\\ -\textbf{Access matrix elements}\\ -\> \texttt{A33.at(i,j) = A33.at(j,i)+1;}\\ -\> \texttt{Mat dyImage(image.size(), image.type());}\\ -\> \texttt{for(int y = 1; y < image.rows-1; y++) \{}\\ -\> \> \texttt{Vec3b* prevRow = image.ptr(y-1);}\\ -\> \> \texttt{Vec3b* nextRow = image.ptr(y+1);}\\ -\> \> \texttt{for(int x = 0; x < image.cols; x++)}\\ -\> \> \> \texttt{for(int c = 0; c < 3; c++)}\\ -\> \> \> \texttt{ dyImage.at(y,x)[c] =}\\ -\> \> \> \texttt{ saturate\_cast(}\\ -\> \> \> \texttt{ nextRow[x][c] - prevRow[x][c]);}\\ -\> \texttt{\} }\\ -\> \texttt{Mat\_::iterator it = image.begin(),}\\ -\> \> \texttt{itEnd = image.end();}\\ -\> \texttt{for(; it != itEnd; ++it)}\\ -\> \> \texttt{(*it)[1] \textasciicircum{}= 255;}\\ - -\end{tabbing} - -\section{Matrix Manipulations: Copying, Shuffling, Part Access} -\begin{tabular}{@{}p{\the\MyLen}% - @{}p{\linewidth-\the\MyLen}@{}} -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#mat-copyto}{src.copyTo(dst)}} & Copy matrix to another one \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#mat-convertto}{src.convertTo(dst,type,scale,shift)}} & \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Scale and convert to another datatype \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#mat-clone}{m.clone()}} & Make deep copy of a matrix \\ -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#mat-reshape}{m.reshape(nch,nrows)}} & Change matrix dimensions and/or number of channels without copying data \\ - -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#mat-row}{m.row(i)}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#mat-col}{m.col(i)}} & Take a matrix row/column \\ - -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#mat-rowrange}{m.rowRange(Range(i1,i2))}} -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#mat-colrange}{m.colRange(Range(j1,j2))}} & \ \ \ \ \ \ \ Take a matrix row/column span \\ - -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#mat-diag}{m.diag(i)}} & Take a matrix diagonal \\ - -\texttt{\href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#Mat}{m(Range(i1,i2),Range(j1,j2)), m(roi)}} & \ \ \ \ \ \ \ \ \ \ \ \ \ Take a submatrix \\ - -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#repeat}{m.repeat(ny,nx)}} & Make a bigger matrix from a smaller one \\ - -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#flip}{flip(src,dst,dir)}} & Reverse the order of matrix rows and/or columns \\ - -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#split}{split(...)}} & Split multi-channel matrix into separate channels \\ - -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#merge}{merge(...)}} & Make a multi-channel matrix out of the separate channels \\ - -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#mixchannels}{mixChannels(...)}} & Generalized form of split() and merge() \\ - -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#randshuffle}{randShuffle(...)}} & Randomly shuffle matrix elements \\ - -\end{tabular} - -\begin{tabbing} -Exa\=mple 1. Smooth image ROI in-place\\ -\>\texttt{Mat imgroi = image(Rect(10, 20, 100, 100));}\\ -\>\texttt{GaussianBlur(imgroi, imgroi, Size(5, 5), 1.2, 1.2);}\\ -Example 2. Somewhere in a linear algebra algorithm \\ -\>\texttt{m.row(i) += m.row(j)*alpha;}\\ -Example 3. Copy image ROI to another image with conversion\\ -\>\texttt{Rect r(1, 1, 10, 20);}\\ -\>\texttt{Mat dstroi = dst(Rect(0,10,r.width,r.height));}\\ -\>\texttt{src(r).convertTo(dstroi, dstroi.type(), 1, 0);}\\ -\end{tabbing} - -\section{Simple Matrix Operations} - -OpenCV implements most common arithmetical, logical and -other matrix operations, such as - -\begin{itemize} -\item -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#add}{add()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#subtract}{subtract()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#multiply}{multiply()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#divide}{divide()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#absdiff}{absdiff()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#bitwise-and}{bitwise\_and()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#bitwise-or}{bitwise\_or()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#bitwise-xor}{bitwise\_xor()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#max}{max()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#min}{min()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#compare}{compare()}} - --- correspondingly, addition, subtraction, element-wise multiplication ... comparison of two matrices or a matrix and a scalar. - -\begin{tabbing} -Exa\=mple. \href{http://en.wikipedia.org/wiki/Alpha_compositing}{Alpha compositing} function:\\ -\texttt{void alphaCompose(const Mat\& rgba1,}\\ -\> \texttt{const Mat\& rgba2, Mat\& rgba\_dest)}\\ -\texttt{\{ }\\ -\> \texttt{Mat a1(rgba1.size(), rgba1.type()), ra1;}\\ -\> \texttt{Mat a2(rgba2.size(), rgba2.type());}\\ -\> \texttt{int mixch[]=\{3, 0, 3, 1, 3, 2, 3, 3\};}\\ -\> \texttt{mixChannels(\&rgba1, 1, \&a1, 1, mixch, 4);}\\ -\> \texttt{mixChannels(\&rgba2, 1, \&a2, 1, mixch, 4);}\\ -\> \texttt{subtract(Scalar::all(255), a1, ra1);}\\ -\> \texttt{bitwise\_or(a1, Scalar(0,0,0,255), a1);}\\ -\> \texttt{bitwise\_or(a2, Scalar(0,0,0,255), a2);}\\ -\> \texttt{multiply(a2, ra1, a2, 1./255);}\\ -\> \texttt{multiply(a1, rgba1, a1, 1./255);}\\ -\> \texttt{multiply(a2, rgba2, a2, 1./255);}\\ -\> \texttt{add(a1, a2, rgba\_dest);}\\ -\texttt{\}} -\end{tabbing} - -\item - -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#sum}{sum()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#mean}{mean()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#meanstddev}{meanStdDev()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#norm}{norm()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#countnonzero}{countNonZero()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#minmaxloc}{minMaxLoc()}}, - --- various statistics of matrix elements. - -\item -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#exp}{exp()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#log}{log()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#pow}{pow()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#sqrt}{sqrt()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#carttopolar}{cartToPolar()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#polartocart}{polarToCart()}} - --- the classical math functions. - -\item -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#scaleadd}{scaleAdd()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#transpose}{transpose()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#gemm}{gemm()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#invert}{invert()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#solve}{solve()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#determinant}{determinant()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#trace}{trace()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#eigen}{eigen()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#SVD}{SVD}}, - --- the algebraic functions + SVD class. - -\item -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#dft}{dft()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#idft}{idft()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#dct}{dct()}}, -\texttt{\href{http://docs.opencv.org/modules/core/doc/operations_on_arrays.html\#idct}{idct()}}, - --- discrete Fourier and cosine transformations - -\end{itemize} - -For some operations a more convenient \href{http://docs.opencv.org/modules/core/doc/basic_structures.html\#matrix-expressions}{algebraic notation} can be used, for example: -\begin{tabbing} -\texttt{Mat}\={} \texttt{delta = (J.t()*J + lambda*}\\ -\>\texttt{Mat::eye(J.cols, J.cols, J.type()))}\\ -\>\texttt{.inv(CV\_SVD)*(J.t()*err);} -\end{tabbing} -implements the core of Levenberg-Marquardt optimization algorithm. - -\section{Image Processsing} - -\subsection{Filtering} - -\begin{tabular}{@{}p{\the\MyLen}% - @{}p{\linewidth-\the\MyLen}@{}} -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#filter2d}{filter2D()}} & Non-separable linear filter \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#sepfilter2d}{sepFilter2D()}} & Separable linear filter \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#blur}{boxFilter()}}, \texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#gaussianblur}{GaussianBlur()}}, -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#medianblur}{medianBlur()}}, -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#bilateralfilter}{bilateralFilter()}} -& Smooth the image with one of the linear or non-linear filters \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#sobel}{Sobel()}}, \texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#scharr}{Scharr()}} -& Compute the spatial image derivatives \\ -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#laplacian}{Laplacian()}} & compute Laplacian: $\Delta I = \frac{\partial ^ 2 I}{\partial x^2} + \frac{\partial ^ 2 I}{\partial y^2}$ \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#erode}{erode()}}, \texttt{\href{http://docs.opencv.org/modules/imgproc/doc/filtering.html\#dilate}{dilate()}} & Morphological operations \\ - -\end{tabular} - -\begin{tabbing} -Exa\=mple. Filter image in-place with a 3x3 high-pass kernel\\ -\> (preserve negative responses by shifting the result by 128):\\ -\texttt{filter2D(image, image, image.depth(), (Mat\_(3,3)<<}\\ -\> \texttt{-1, -1, -1, -1, 9, -1, -1, -1, -1), Point(1,1), 128);}\\ -\end{tabbing} - -\subsection{Geometrical Transformations} - -\begin{tabular}{@{}p{\the\MyLen}% - @{}p{\linewidth-\the\MyLen}@{}} -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html\#resize}{resize()}} & Resize image \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html\#getrectsubpix}{getRectSubPix()}} & Extract an image patch \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html\#warpaffine}{warpAffine()}} & Warp image affinely\\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html\#warpperspective}{warpPerspective()}} & Warp image perspectively\\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html\#remap}{remap()}} & Generic image warping\\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html\#convertmaps}{convertMaps()}} & Optimize maps for a faster remap() execution\\ - -\end{tabular} - -\begin{tabbing} -Example. Decimate image by factor of $\sqrt{2}$:\\ -\texttt{Mat dst; resize(src, dst, Size(), 1./sqrt(2), 1./sqrt(2));} -\end{tabbing} - -\subsection{Various Image Transformations} - -\begin{tabular}{@{}p{\the\MyLen}% - @{}p{\linewidth-\the\MyLen}@{}} - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html\#cvtcolor}{cvtColor()}} & Convert image from one color space to another \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html\#threshold}{threshold()}}, \texttt{\href{http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html\#adaptivethreshold}{adaptivethreshold()}} & Convert grayscale image to binary image using a fixed or a variable threshold \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html\#floodfill}{floodFill()}} & Find a connected component using region growing algorithm\\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html\#integral}{integral()}} & Compute integral image \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html\#distancetransform}{distanceTransform()}} - & build distance map or discrete Voronoi diagram for a binary image. \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html\#watershed}{watershed()}}, -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html\#grabcut}{grabCut()}} - & marker-based image segmentation algorithms. - See the samples \texttt{\href{https://github.com/Itseez/opencv/tree/master/samples/cpp/watershed.cpp}{watershed.cpp}} and \texttt{\href{https://github.com/Itseez/opencv/tree/master/samples/cpp/grabcut.cpp}{grabcut.cpp}}. - -\end{tabular} - -\subsection{Histograms} - -\begin{tabular}{@{}p{\the\MyLen}% - @{}p{\linewidth-\the\MyLen}@{}} - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/histograms.html\#calchist}{calcHist()}} & Compute image(s) histogram \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/histograms.html\#calcbackproject}{calcBackProject()}} & Back-project the histogram \\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/histograms.html\#equalizehist}{equalizeHist()}} & Normalize image brightness and contrast\\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/histograms.html\#comparehist}{compareHist()}} & Compare two histograms\\ - -\end{tabular} - -\begin{tabbing} -Example. Compute Hue-Saturation histogram of an image:\\ -\texttt{Mat hsv, H;}\\ -\texttt{cvtColor(image, hsv, CV\_BGR2HSV);}\\ -\texttt{int planes[]=\{0, 1\}, hsize[] = \{32, 32\};}\\ -\texttt{calcHist(\&hsv, 1, planes, Mat(), H, 2, hsize, 0);}\\ -\end{tabbing} - -\subsection{Contours} -See \texttt{\href{https://github.com/Itseez/opencv/tree/master/samples/cpp/contours2.cpp}{contours2.cpp}} and \texttt{\href{https://github.com/Itseez/opencv/tree/master/samples/cpp/squares.cpp}{squares.cpp}} -samples on what are the contours and how to use them. - -\section{Data I/O} - -\href{http://docs.opencv.org/modules/core/doc/xml_yaml_persistence.html\#xml-yaml-file-storages-writing-to-a-file-storage}{XML/YAML storages} are collections (possibly nested) of scalar values, structures and heterogeneous lists. - -\begin{tabbing} -\textbf{Wr}\=\textbf{iting data to YAML (or XML)}\\ -\texttt{// Type of the file is determined from the extension}\\ -\texttt{FileStorage fs("test.yml", FileStorage::WRITE);}\\ -\texttt{fs << "i" << 5 << "r" << 3.1 << "str" << "ABCDEFGH";}\\ -\texttt{fs << "mtx" << Mat::eye(3,3,CV\_32F);}\\ -\texttt{fs << "mylist" << "[" << CV\_PI << "1+1" <<}\\ -\>\texttt{"\{:" << "month" << 12 << "day" << 31 << "year"}\\ -\>\texttt{<< 1969 << "\}" << "]";}\\ -\texttt{fs << "mystruct" << "\{" << "x" << 1 << "y" << 2 <<}\\ -\>\texttt{"width" << 100 << "height" << 200 << "lbp" << "[:";}\\ -\texttt{const uchar arr[] = \{0, 1, 1, 0, 1, 1, 0, 1\};}\\ -\texttt{fs.writeRaw("u", arr, (int)(sizeof(arr)/sizeof(arr[0])));}\\ -\texttt{fs << "]" << "\}";} -\end{tabbing} - -\emph{Scalars (integers, floating-point numbers, text strings), matrices, STL vectors of scalars and some other types can be written to the file storages using \texttt{<<} operator} - -\begin{tabbing} -\textbf{Re}\=\textbf{ading the data back}\\ -\texttt{// Type of the file is determined from the content}\\ -\texttt{FileStorage fs("test.yml", FileStorage::READ);}\\ -\texttt{int i1 = (int)fs["i"]; double r1 = (double)fs["r"];}\\ -\texttt{string str1 = (string)fs["str"];}\\ - -\texttt{Mat M; fs["mtx"] >> M;}\\ - -\texttt{FileNode tl = fs["mylist"];}\\ -\texttt{CV\_Assert(tl.type() == FileNode::SEQ \&\& tl.size() == 3);}\\ -\texttt{double tl0 = (double)tl[0]; string tl1 = (string)tl[1];}\\ - -\texttt{int m = (int)tl[2]["month"], d = (int)tl[2]["day"];}\\ -\texttt{int year = (int)tl[2]["year"];}\\ - -\texttt{FileNode tm = fs["mystruct"];}\\ - -\texttt{Rect r; r.x = (int)tm["x"], r.y = (int)tm["y"];}\\ -\texttt{r.width = (int)tm["width"], r.height = (int)tm["height"];}\\ - -\texttt{int lbp\_val = 0;}\\ -\texttt{FileNodeIterator it = tm["lbp"].begin();}\\ - -\texttt{for(int k = 0; k < 8; k++, ++it)}\\ -\>\texttt{lbp\_val |= ((int)*it) << k;}\\ -\end{tabbing} - -\emph{Scalars are read using the corresponding FileNode's cast operators. Matrices and some other types are read using \texttt{>>} operator. Lists can be read using FileNodeIterator's.} - -\begin{tabbing} -\textbf{Wr}\=\textbf{iting and reading raster images}\\ -\texttt{\href{http://docs.opencv.org/modules/imgcodecs/doc/reading_and_writing_images.html\#imwrite}{imwrite}("myimage.jpg", image);}\\ -\texttt{Mat image\_color\_copy = \href{http://docs.opencv.org/modules/imgcodecs/doc/reading_and_writing_images.html\#imread}{imread}("myimage.jpg", 1);}\\ -\texttt{Mat image\_grayscale\_copy = \href{http://docs.opencv.org/modules/imgcodecs/doc/reading_and_writing_images.html\#imread}{imread}("myimage.jpg", 0);}\\ -\end{tabbing} - -\emph{The functions can read/write images in the following formats: \textbf{BMP (.bmp), JPEG (.jpg, .jpeg), TIFF (.tif, .tiff), PNG (.png), PBM/PGM/PPM (.p?m), Sun Raster (.sr), JPEG 2000 (.jp2)}. Every format supports 8-bit, 1- or 3-channel images. Some formats (PNG, JPEG 2000) support 16 bits per channel.} - -\begin{tabbing} -\textbf{Re}\=\textbf{ading video from a file or from a camera}\\ -\texttt{VideoCapture cap;}\\ -\texttt{if(argc > 1) cap.open(string(argv[1])); else cap.open(0)};\\ -\texttt{Mat frame; namedWindow("video", 1);}\\ -\texttt{for(;;) \{}\\ -\>\texttt{cap >> frame; if(!frame.data) break;}\\ -\>\texttt{imshow("video", frame); if(waitKey(30) >= 0) break;}\\ -\texttt{\} } -\end{tabbing} - -\section{Simple GUI (highgui module)} - -\begin{tabular}{@{}p{\the\MyLen}% - @{}p{\linewidth-\the\MyLen}@{}} - -\texttt{\href{http://docs.opencv.org/modules/highgui/doc/user_interface.html\#namedwindow}{namedWindow(winname,flags)}} & \ \ \ \ \ \ \ \ \ \ Create named highgui window \\ - -\texttt{\href{http://docs.opencv.org/modules/highgui/doc/user_interface.html\#destroywindow}{destroyWindow(winname)}} & \ \ \ Destroy the specified window \\ - -\texttt{\href{http://docs.opencv.org/modules/highgui/doc/user_interface.html\#imshow}{imshow(winname, mtx)}} & Show image in the window \\ - -\texttt{\href{http://docs.opencv.org/modules/highgui/doc/user_interface.html\#waitkey}{waitKey(delay)}} & Wait for a key press during the specified time interval (or forever). Process events while waiting. \emph{Do not forget to call this function several times a second in your code.} \\ - -\texttt{\href{http://docs.opencv.org/modules/highgui/doc/user_interface.html\#createtrackbar}{createTrackbar(...)}} & Add trackbar (slider) to the specified window \\ - -\texttt{\href{http://docs.opencv.org/modules/highgui/doc/user_interface.html\#setmousecallback}{setMouseCallback(...)}} & \ \ Set the callback on mouse clicks and movements in the specified window \\ - -\end{tabular} - -See \texttt{\href{https://github.com/Itseez/opencv/tree/master/samples/cpp/camshiftdemo.cpp}{camshiftdemo.cpp}} and other \href{https://github.com/Itseez/opencv/tree/master/samples/}{OpenCV samples} on how to use the GUI functions. - -\section{Camera Calibration, Pose Estimation and Depth Estimation} - -\begin{tabular}{@{}p{\the\MyLen}% - @{}p{\linewidth-\the\MyLen}@{}} - -\texttt{\href{http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html\#calibratecamera}{calibrateCamera()}} & Calibrate camera from several views of a calibration pattern. \\ - -\texttt{\href{http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html\#findchessboardcorners}{findChessboardCorners()}} & \ \ \ \ \ \ Find feature points on the checkerboard calibration pattern. \\ - -\texttt{\href{http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html\#solvepnp}{solvePnP()}} & Find the object pose from the known projections of its feature points. \\ - -\texttt{\href{http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html\#stereocalibrate}{stereoCalibrate()}} & Calibrate stereo camera. \\ - -\texttt{\href{http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html\#stereorectify}{stereoRectify()}} & Compute the rectification transforms for a calibrated stereo camera.\\ - -\texttt{\href{http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html\#initundistortrectifymap}{initUndistortRectifyMap()}} & \ \ \ \ \ \ Compute rectification map (for \texttt{remap()}) for each stereo camera head.\\ - -\texttt{\href{http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html\#StereoBM}{StereoBM}}, \texttt{\href{http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html\#StereoSGBM}{StereoSGBM}} & The stereo correspondence engines to be run on rectified stereo pairs.\\ - -\texttt{\href{http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html\#reprojectimageto3d}{reprojectImageTo3D()}} & Convert disparity map to 3D point cloud.\\ - -\texttt{\href{http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html\#findhomography}{findHomography()}} & Find best-fit perspective transformation between two 2D point sets. \\ - -\end{tabular} - -To calibrate a camera, you can use \texttt{\href{https://github.com/Itseez/opencv/tree/master/samples/cpp/calibration.cpp}{calibration.cpp}} or -\texttt{\href{https://github.com/Itseez/opencv/tree/master/samples/cpp/stereo\_calib.cpp}{stereo\_calib.cpp}} samples. -To get the disparity maps and the point clouds, use -\texttt{\href{https://github.com/Itseez/opencv/tree/master/samples/cpp/stereo\_match.cpp}{stereo\_match.cpp}} sample. - -\section{Object Detection} - -\begin{tabular}{@{}p{\the\MyLen}% - @{}p{\linewidth-\the\MyLen}@{}} - \texttt{\href{http://docs.opencv.org/modules/imgproc/doc/object_detection.html\#matchtemplate}{matchTemplate}} & Compute proximity map for given template.\\ - -\texttt{\href{http://docs.opencv.org/modules/objdetect/doc/cascade_classification.html\#cascadeclassifier}{CascadeClassifier}} & Viola's Cascade of Boosted classifiers using Haar or LBP features. Suits for detecting faces, facial features and some other objects without diverse textures. See \texttt{\href{https://github.com/Itseez/opencv/tree/master/samples/c/facedetect.cpp}{facedetect.cpp}}\\ - -\texttt{{HOGDescriptor}} & N. Dalal's object detector using Histogram-of-Oriented-Gradients (HOG) features. Suits for detecting people, cars and other objects with well-defined silhouettes. See \texttt{\href{https://github.com/Itseez/opencv/tree/master/samples/cpp/peopledetect.cpp}{peopledetect.cpp}}\\ - -\end{tabular} - -% -% feature detection: -% features2d toolbox -% -% object detection: -% using a classifier running on a sliding window: cascadeclassifier + hog. -% using salient point features: features2d -> matching -% -% statistical data processing: -% clustering (k-means), -% classification + regression (SVM, boosting, k-nearest), -% compressing data (PCA) - -\end{multicols} -\end{document} diff --git a/doc/packaging.txt b/doc/packaging.txt deleted file mode 100644 index a27119b097..0000000000 --- a/doc/packaging.txt +++ /dev/null @@ -1,17 +0,0 @@ - -INSTRUCTIONS TO BUILD WIN32 PACKAGES WITH CMAKE+CPACK ------------------------------------------------------- - -- Install NSIS. -- Generate OpenCV solutions for MSVC using CMake as usual. -- In cmake-gui: - - Mark BUILD_PACKAGE - - Mark BUILD_EXAMPLES (If examples are desired to be shipped as binaries...) - - Unmark ENABLE_OPENMP, since this feature seems to have some issues yet... - - Mark INSTALL_*_EXAMPLES -- Open the OpenCV solution and build ALL in Debug and Release. -- Build PACKAGE, from the Release configuration. An NSIS installer package will be - created with both release and debug LIBs and DLLs. - - -Jose Luis Blanco, 2009/JUL/29 diff --git a/doc/patch_refman_latex.py b/doc/patch_refman_latex.py deleted file mode 100755 index ff762fc8f3..0000000000 --- a/doc/patch_refman_latex.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -import sys - -f=open(sys.argv[1], "rt") -ll = list(f.readlines()) -f.close() -f=open(sys.argv[1], "wt") -singleparam = False - -for l in ll: - l = l.replace("\\code{~const}}{}", "}{\\code{~const}}") - if l.startswith("\\item[{Parameters}] \\leavevmode"): - if not l.startswith("\\item[{Parameters}] \\leavevmode\\begin{itemize}"): - singleparam = True - l = "\\item[{Parameters}] \\leavevmode\\begin{itemize}[label=]\n" - if singleparam: - l += "\\item {}\n" - elif singleparam and l.startswith("\\end{description}\\end{quote}"): - l = "\\end{itemize}\n" + l - singleparam = False - f.write(l) - -f.close() diff --git a/doc/py_tutorials/py_bindings/py_table_of_contents_bindings/images/nlm_icon.jpg b/doc/py_tutorials/py_bindings/images/nlm_icon.jpg similarity index 100% rename from doc/py_tutorials/py_bindings/py_table_of_contents_bindings/images/nlm_icon.jpg rename to doc/py_tutorials/py_bindings/images/nlm_icon.jpg diff --git a/doc/py_tutorials/py_bindings/py_bindings_basics/py_bindings_basics.rst b/doc/py_tutorials/py_bindings/py_bindings_basics/py_bindings_basics.rst deleted file mode 100644 index 94832613e2..0000000000 --- a/doc/py_tutorials/py_bindings/py_bindings_basics/py_bindings_basics.rst +++ /dev/null @@ -1,112 +0,0 @@ -.. _Bindings_Basics: - -How OpenCV-Python Bindings Works? -************************************ - -Goal -===== - -Learn: - - * How OpenCV-Python bindings are generated? - * How to extend new OpenCV modules to Python? - -How OpenCV-Python bindings are generated? -========================================= - -In OpenCV, all algorithms are implemented in C++. But these algorithms can be used from different languages like Python, Java etc. This is made possible by the bindings generators. These generators create a bridge between C++ and Python which enables users to call C++ functions from Python. To get a complete picture of what is happening in background, a good knowledge of Python/C API is required. A simple example on extending C++ functions to Python can be found in official Python documentation[1]. So extending all functions in OpenCV to Python by writing their wrapper functions manually is a time-consuming task. So OpenCV does it in a more intelligent way. OpenCV generates these wrapper functions automatically from the C++ headers using some Python scripts which are located in ``modules/python/src2``. We will look into what they do. - -First, ``modules/python/CMakeFiles.txt`` is a CMake script which checks the modules to be extended to Python. It will automatically check all the modules to be extended and grab their header files. These header files contain list of all classes, functions, constants etc. for that particular modules. - -Second, these header files are passed to a Python script, ``modules/python/src2/gen2.py``. This is the Python bindings generator script. It calls another Python script ``modules/python/src2/hdr_parser.py``. This is the header parser script. This header parser splits the complete header file into small Python lists. So these lists contain all details about a particular function, class etc. For example, a function will be parsed to get a list containing function name, return type, input arguments, argument types etc. Final list contains details of all the functions, structs, classes etc. in that header file. - -But header parser doesn't parse all the functions/classes in the header file. The developer has to specify which functions should be exported to Python. For that, there are certain macros added to the beginning of these declarations which enables the header parser to identify functions to be parsed. These macros are added by the developer who programs the particular function. In short, the developer decides which functions should be extended to Python and which are not. Details of those macros will be given in next session. - -So header parser returns a final big list of parsed functions. Our generator script (gen2.py) will create wrapper functions for all the functions/classes/enums/structs parsed by header parser (You can find these header files during compilation in the ``build/modules/python/`` folder as ``pyopencv_generated_*.h`` files). But there may be some basic OpenCV datatypes like Mat, Vec4i, Size. They need to be extended manually. For example, a Mat type should be extended to Numpy array, Size should be extended to a tuple of two integers etc. Similarly, there may be some complex structs/classes/functions etc. which need to be extended manually. All such manual wrapper functions are placed in ``modules/python/src2/pycv2.hpp``. - -So now only thing left is the compilation of these wrapper files which gives us **cv2** module. So when you call a function, say ``res = equalizeHist(img1,img2)`` in Python, you pass two numpy arrays and you expect another numpy array as the output. So these numpy arrays are converted to ``cv::Mat`` and then calls the ``equalizeHist()`` function in C++. Final result, ``res`` will be converted back into a Numpy array. So in short, almost all operations are done in C++ which gives us almost same speed as that of C++. - -So this is the basic version of how OpenCV-Python bindings are generated. - - -How to extend new modules to Python? -===================================== - -Header parser parse the header files based on some wrapper macros added to function declaration. Enumeration constants don't need any wrapper macros. They are automatically wrapped. But remaining functions, classes etc. need wrapper macros. - -Functions are extended using ``CV_EXPORTS_W`` macro. An example is shown below. - -.. code-block:: cpp - - CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst ); - -Header parser can understand the input and output arguments from keywords like ``InputArray, OutputArray`` etc. But sometimes, we may need to hardcode inputs and outputs. For that, macros like ``CV_OUT, CV_IN_OUT`` etc. are used. - -.. code-block:: cpp - - CV_EXPORTS_W void minEnclosingCircle( InputArray points, - CV_OUT Point2f& center, CV_OUT float& radius ); - -For large classes also, ``CV_EXPORTS_W`` is used. To extend class methods, ``CV_WRAP`` is used. Similarly, ``CV_PROP`` is used for class fields. - -.. code-block:: cpp - - class CV_EXPORTS_W CLAHE : public Algorithm - { - public: - CV_WRAP virtual void apply(InputArray src, OutputArray dst) = 0; - - CV_WRAP virtual void setClipLimit(double clipLimit) = 0; - CV_WRAP virtual double getClipLimit() const = 0; - } - -Overloaded functions can be extended using ``CV_EXPORTS_AS``. But we need to pass a new name so that each function will be called by that name in Python. Take the case of integral function below. Three functions are available, so each one is named with a suffix in Python. Similarly ``CV_WRAP_AS`` can be used to wrap overloaded methods. - -.. code-block:: cpp - - //! computes the integral image - CV_EXPORTS_W void integral( InputArray src, OutputArray sum, int sdepth = -1 ); - - //! computes the integral image and integral for the squared image - CV_EXPORTS_AS(integral2) void integral( InputArray src, OutputArray sum, - OutputArray sqsum, int sdepth = -1, int sqdepth = -1 ); - - //! computes the integral image, integral for the squared image and the tilted integral image - CV_EXPORTS_AS(integral3) void integral( InputArray src, OutputArray sum, - OutputArray sqsum, OutputArray tilted, - int sdepth = -1, int sqdepth = -1 ); - -Small classes/structs are extended using ``CV_EXPORTS_W_SIMPLE``. These structs are passed by value to C++ functions. Examples are KeyPoint, Match etc. Their methods are extended by ``CV_WRAP`` and fields are extended by ``CV_PROP_RW``. - -.. code-block:: cpp - - class CV_EXPORTS_W_SIMPLE DMatch - { - public: - CV_WRAP DMatch(); - CV_WRAP DMatch(int _queryIdx, int _trainIdx, float _distance); - CV_WRAP DMatch(int _queryIdx, int _trainIdx, int _imgIdx, float _distance); - - CV_PROP_RW int queryIdx; // query descriptor index - CV_PROP_RW int trainIdx; // train descriptor index - CV_PROP_RW int imgIdx; // train image index - - CV_PROP_RW float distance; - }; - -Some other small classes/structs can be exported using ``CV_EXPORTS_W_MAP`` where it is exported to a Python native dictionary. Moments() is an example of it. - -.. code-block:: cpp - - class CV_EXPORTS_W_MAP Moments - { - public: - //! spatial moments - CV_PROP_RW double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03; - //! central moments - CV_PROP_RW double mu20, mu11, mu02, mu30, mu21, mu12, mu03; - //! central normalized moments - CV_PROP_RW double nu20, nu11, nu02, nu30, nu21, nu12, nu03; - }; - -So these are the major extension macros available in OpenCV. Typically, a developer has to put proper macros in their appropriate positions. Rest is done by generator scripts. Sometimes, there may be an exceptional cases where generator scripts cannot create the wrappers. Such functions need to be handled manually. But most of the time, a code written according to OpenCV coding guidelines will be automatically wrapped by generator scripts. diff --git a/doc/py_tutorials/py_bindings/py_table_of_contents_bindings/py_table_of_contents_bindings.markdown b/doc/py_tutorials/py_bindings/py_table_of_contents_bindings.markdown similarity index 100% rename from doc/py_tutorials/py_bindings/py_table_of_contents_bindings/py_table_of_contents_bindings.markdown rename to doc/py_tutorials/py_bindings/py_table_of_contents_bindings.markdown diff --git a/doc/py_tutorials/py_bindings/py_table_of_contents_bindings/py_table_of_contents_bindings.rst b/doc/py_tutorials/py_bindings/py_table_of_contents_bindings/py_table_of_contents_bindings.rst deleted file mode 100644 index c5fccca0a5..0000000000 --- a/doc/py_tutorials/py_bindings/py_table_of_contents_bindings/py_table_of_contents_bindings.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _PY_Table-Of-Content-Bindings: - - -OpenCV-Python Bindings --------------------------------- - -Here, you will learn how OpenCV-Python bindings are generated. - - -* :ref:`Bindings_Basics` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |bind1| Learn how OpenCV-Python bindings are generated. - - =========== ====================================================== - - .. |bind1| image:: images/nlm_icon.jpg - :height: 90pt - :width: 90pt - - - - - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_bindings_basics/py_bindings_basics diff --git a/doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/images/calibration_icon.jpg b/doc/py_tutorials/py_calib3d/images/calibration_icon.jpg similarity index 100% rename from doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/images/calibration_icon.jpg rename to doc/py_tutorials/py_calib3d/images/calibration_icon.jpg diff --git a/doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/images/depthmap_icon.jpg b/doc/py_tutorials/py_calib3d/images/depthmap_icon.jpg similarity index 100% rename from doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/images/depthmap_icon.jpg rename to doc/py_tutorials/py_calib3d/images/depthmap_icon.jpg diff --git a/doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/images/epipolar_icon.jpg b/doc/py_tutorials/py_calib3d/images/epipolar_icon.jpg similarity index 100% rename from doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/images/epipolar_icon.jpg rename to doc/py_tutorials/py_calib3d/images/epipolar_icon.jpg diff --git a/doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/images/pose_icon.jpg b/doc/py_tutorials/py_calib3d/images/pose_icon.jpg similarity index 100% rename from doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/images/pose_icon.jpg rename to doc/py_tutorials/py_calib3d/images/pose_icon.jpg diff --git a/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.rst b/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.rst deleted file mode 100644 index 4f0e7cc067..0000000000 --- a/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.rst +++ /dev/null @@ -1,213 +0,0 @@ -.. _calibration: - - -Camera Calibration -******************** - -Goal -======= - -In this section, - * We will learn about distortions in camera, intrinsic and extrinsic parameters of camera etc. - * We will learn to find these parameters, undistort images etc. - - -Basics -======== - -Today's cheap pinhole cameras introduces a lot of distortion to images. Two major distortions are radial distortion and tangential distortion. - -Due to radial distortion, straight lines will appear curved. Its effect is more as we move away from the center of image. For example, one image is shown below, where two edges of a chess board are marked with red lines. But you can see that border is not a straight line and doesn't match with the red line. All the expected straight lines are bulged out. Visit `Distortion (optics) `_ for more details. - - .. image:: images/calib_radial.jpg - :alt: Radial Distortion - :align: center - -This distortion is solved as follows: - -.. math:: - - x_{corrected} = x( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6) \\ - y_{corrected} = y( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6) - - -Similarly, another distortion is the tangential distortion which occurs because image taking lense is not aligned perfectly parallel to the imaging plane. So some areas in image may look nearer than expected. It is solved as below: - - -.. math:: - - x_{corrected} = x + [ 2p_1xy + p_2(r^2+2x^2)] \\ - y_{corrected} = y + [ p_1(r^2+ 2y^2)+ 2p_2xy] - - -In short, we need to find five parameters, known as distortion coefficients given by: - -.. math:: - - Distortion \; coefficients=(k_1 \hspace{10pt} k_2 \hspace{10pt} p_1 \hspace{10pt} p_2 \hspace{10pt} k_3) - - -In addition to this, we need to find a few more information, like intrinsic and extrinsic parameters of a camera. Intrinsic parameters are specific to a camera. It includes information like focal length (:math:`f_x,f_y`), optical centers (:math:`c_x, c_y`) etc. It is also called camera matrix. It depends on the camera only, so once calculated, it can be stored for future purposes. It is expressed as a 3x3 matrix: - -.. math:: - - camera \; matrix = \left [ \begin{matrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix} \right ] - - -Extrinsic parameters corresponds to rotation and translation vectors which translates a coordinates of a 3D point to a coordinate system. - - -For stereo applications, these distortions need to be corrected first. To find all these parameters, what we have to do is to provide some sample images of a well defined pattern (eg, chess board). We find some specific points in it ( square corners in chess board). We know its coordinates in real world space and we know its coordinates in image. With these data, some mathematical problem is solved in background to get the distortion coefficients. That is the summary of the whole story. For better results, we need atleast 10 test patterns. - - -Code -======== - -As mentioned above, we need atleast 10 test patterns for camera calibration. OpenCV comes with some images of chess board (see ``samples/cpp/left01.jpg -- left14.jpg``), so we will utilize it. For sake of understanding, consider just one image of a chess board. Important input datas needed for camera calibration is a set of 3D real world points and its corresponding 2D image points. 2D image points are OK which we can easily find from the image. (These image points are locations where two black squares touch each other in chess boards) - -What about the 3D points from real world space? Those images are taken from a static camera and chess boards are placed at different locations and orientations. So we need to know :math:`(X,Y,Z)` values. But for simplicity, we can say chess board was kept stationary at XY plane, (so Z=0 always) and camera was moved accordingly. This consideration helps us to find only X,Y values. Now for X,Y values, we can simply pass the points as (0,0), (1,0), (2,0), ... which denotes the location of points. In this case, the results we get will be in the scale of size of chess board square. But if we know the square size, (say 30 mm), and we can pass the values as (0,0),(30,0),(60,0),..., we get the results in mm. (In this case, we don't know square size since we didn't take those images, so we pass in terms of square size). - -3D points are called **object points** and 2D image points are called **image points.** - -Setup ---------- - -So to find pattern in chess board, we use the function, **cv2.findChessboardCorners()**. We also need to pass what kind of pattern we are looking, like 8x8 grid, 5x5 grid etc. In this example, we use 7x6 grid. (Normally a chess board has 8x8 squares and 7x7 internal corners). It returns the corner points and retval which will be True if pattern is obtained. These corners will be placed in an order (from left-to-right, top-to-bottom) - -.. seealso:: This function may not be able to find the required pattern in all the images. So one good option is to write the code such that, it starts the camera and check each frame for required pattern. Once pattern is obtained, find the corners and store it in a list. Also provides some interval before reading next frame so that we can adjust our chess board in different direction. Continue this process until required number of good patterns are obtained. Even in the example provided here, we are not sure out of 14 images given, how many are good. So we read all the images and take the good ones. - -.. seealso:: Instead of chess board, we can use some circular grid, but then use the function **cv2.findCirclesGrid()** to find the pattern. It is said that less number of images are enough when using circular grid. - -Once we find the corners, we can increase their accuracy using **cv2.cornerSubPix()**. We can also draw the pattern using **cv2.drawChessboardCorners()**. All these steps are included in below code: - -:: - - import numpy as np - import cv2 - import glob - - # termination criteria - criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) - - # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0) - objp = np.zeros((6*7,3), np.float32) - objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2) - - # Arrays to store object points and image points from all the images. - objpoints = [] # 3d point in real world space - imgpoints = [] # 2d points in image plane. - - images = glob.glob('*.jpg') - - for fname in images: - img = cv2.imread(fname) - gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - - # Find the chess board corners - ret, corners = cv2.findChessboardCorners(gray, (7,6),None) - - # If found, add object points, image points (after refining them) - if ret == True: - objpoints.append(objp) - - cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria) - imgpoints.append(corners) - - # Draw and display the corners - cv2.drawChessboardCorners(img, (7,6), corners2,ret) - cv2.imshow('img',img) - cv2.waitKey(500) - - cv2.destroyAllWindows() - -One image with pattern drawn on it is shown below: - - .. image:: images/calib_pattern.jpg - :alt: Calibration Pattern - :align: center - - -Calibration ------------- - -So now we have our object points and image points we are ready to go for calibration. For that we use the function, **cv2.calibrateCamera()**. It returns the camera matrix, distortion coefficients, rotation and translation vectors etc. -:: - - ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None) - - -Undistortion ---------------- - -We have got what we were trying. Now we can take an image and undistort it. OpenCV comes with two methods, we will see both. But before that, we can refine the camera matrix based on a free scaling parameter using **cv2.getOptimalNewCameraMatrix()**. If the scaling parameter ``alpha=0``, it returns undistorted image with minimum unwanted pixels. So it may even remove some pixels at image corners. If ``alpha=1``, all pixels are retained with some extra black images. It also returns an image ROI which can be used to crop the result. - -So we take a new image (``left12.jpg`` in this case. That is the first image in this chapter) -:: - - img = cv2.imread('left12.jpg') - h, w = img.shape[:2] - newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h)) - -1. Using **cv2.undistort()** -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This is the shortest path. Just call the function and use ROI obtained above to crop the result. -:: - - # undistort - dst = cv2.undistort(img, mtx, dist, None, newcameramtx) - - # crop the image - x,y,w,h = roi - dst = dst[y:y+h, x:x+w] - cv2.imwrite('calibresult.png',dst) - - -2. Using **remapping** -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This is curved path. First find a mapping function from distorted image to undistorted image. Then use the remap function. -:: - - # undistort - mapx,mapy = cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5) - dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR) - - # crop the image - x,y,w,h = roi - dst = dst[y:y+h, x:x+w] - cv2.imwrite('calibresult.png',dst) - -Both the methods give the same result. See the result below: - - .. image:: images/calib_result.jpg - :alt: Calibration Result - :align: center - -You can see in the result that all the edges are straight. - -Now you can store the camera matrix and distortion coefficients using write functions in Numpy (np.savez, np.savetxt etc) for future uses. - -Re-projection Error -======================= -Re-projection error gives a good estimation of just how exact is the found parameters. This should be as close to zero as possible. Given the intrinsic, distortion, rotation and translation matrices, we first transform the object point to image point using **cv2.projectPoints()**. Then we calculate the absolute norm between what we got with our transformation and the corner finding algorithm. To find the average error we calculate the arithmetical mean of the errors calculate for all the calibration images. -:: - - mean_error = 0 - for i in xrange(len(objpoints)): - imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) - error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2) - tot_error += error - - print "total error: ", mean_error/len(objpoints) - - -Additional Resources -====================== - - - -Exercises -============ - -#. Try camera calibration with circular grid. diff --git a/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.rst b/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.rst deleted file mode 100644 index 803ac37696..0000000000 --- a/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.rst +++ /dev/null @@ -1,67 +0,0 @@ -.. _py_depthmap: - - -Depth Map from Stereo Images -****************************** - -Goal -======= - -In this session, - * We will learn to create depth map from stereo images. - - -Basics -=========== -In last session, we saw basic concepts like epipolar constraints and other related terms. We also saw that if we have two images of same scene, we can get depth information from that in an intuitive way. Below is an image and some simple mathematical formulas which proves that intuition. (Image Courtesy : - - .. image:: images/stereo_depth.jpg - :alt: Calculating depth - :align: center - -The above diagram contains equivalent triangles. Writing their equivalent equations will yield us following result: - -.. math:: - - disparity = x - x' = \frac{Bf}{Z} - -:math:`x` and :math:`x'` are the distance between points in image plane corresponding to the scene point 3D and their camera center. :math:`B` is the distance between two cameras (which we know) and :math:`f` is the focal length of camera (already known). So in short, above equation says that the depth of a point in a scene is inversely proportional to the difference in distance of corresponding image points and their camera centers. So with this information, we can derive the depth of all pixels in an image. - -So it finds corresponding matches between two images. We have already seen how epiline constraint make this operation faster and accurate. Once it finds matches, it finds the disparity. Let's see how we can do it with OpenCV. - - -Code -======== - -Below code snippet shows a simple procedure to create disparity map. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - imgL = cv2.imread('tsukuba_l.png',0) - imgR = cv2.imread('tsukuba_r.png',0) - - stereo = cv2.createStereoBM(numDisparities=16, blockSize=15) - disparity = stereo.compute(imgL,imgR) - plt.imshow(disparity,'gray') - plt.show() - -Below image contains the original image (left) and its disparity map (right). As you can see, result is contaminated with high degree of noise. By adjusting the values of numDisparities and blockSize, you can get a better result. - - .. image:: images/disparity_map.jpg - :alt: Disparity Map - :align: center - -.. note:: More details to be added - - -Additional Resources -============================= - - -Exercises -============ - -1. OpenCV samples contain an example of generating disparity map and its 3D reconstruction. Check ``stereo_match.py`` in OpenCV-Python samples. diff --git a/doc/py_tutorials/py_calib3d/py_epipolar_geometry/py_epipolar_geometry.rst b/doc/py_tutorials/py_calib3d/py_epipolar_geometry/py_epipolar_geometry.rst deleted file mode 100644 index e017bd6fec..0000000000 --- a/doc/py_tutorials/py_calib3d/py_epipolar_geometry/py_epipolar_geometry.rst +++ /dev/null @@ -1,158 +0,0 @@ -.. _epipolar_geometry: - - -Epipolar Geometry -********************* - - -Goal -======== -In this section, - - * We will learn about the basics of multiview geometry - * We will see what is epipole, epipolar lines, epipolar constraint etc. - - -Basic Concepts -================= - -When we take an image using pin-hole camera, we loose an important information, ie depth of the image. Or how far is each point in the image from the camera because it is a 3D-to-2D conversion. So it is an important question whether we can find the depth information using these cameras. And the answer is to use more than one camera. Our eyes works in similar way where we use two cameras (two eyes) which is called stereo vision. So let's see what OpenCV provides in this field. - -(*Learning OpenCV* by Gary Bradsky has a lot of information in this field.) - -Before going to depth images, let's first understand some basic concepts in multiview geometry. In this section we will deal with epipolar geometry. See the image below which shows a basic setup with two cameras taking the image of same scene. - - .. image:: images/epipolar.jpg - :alt: Epipolar geometry - :align: center - - -If we are using only the left camera, we can't find the 3D point corresponding to the point :math:`x` in image because every point on the line :math:`OX` projects to the same point on the image plane. But consider the right image also. Now different points on the line :math:`OX` projects to different points (:math:`x'`) in right plane. So with these two images, we can triangulate the correct 3D point. This is the whole idea. - -The projection of the different points on :math:`OX` form a line on right plane (line :math:`l'`). We call it **epiline** corresponding to the point :math:`x`. It means, to find the point :math:`x` on the right image, search along this epiline. It should be somewhere on this line (Think of it this way, to find the matching point in other image, you need not search the whole image, just search along the epiline. So it provides better performance and accuracy). This is called **Epipolar Constraint**. Similarly all points will have its corresponding epilines in the other image. The plane :math:`XOO'` is called **Epipolar Plane**. - -:math:`O` and :math:`O'` are the camera centers. From the setup given above, you can see that projection of right camera :math:`O'` is seen on the left image at the point, :math:`e`. It is called the **epipole**. Epipole is the point of intersection of line through camera centers and the image planes. Similarly :math:`e'` is the epipole of the left camera. In some cases, you won't be able to locate the epipole in the image, they may be outside the image (which means, one camera doesn't see the other). - -All the epilines pass through its epipole. So to find the location of epipole, we can find many epilines and find their intersection point. - -So in this session, we focus on finding epipolar lines and epipoles. But to find them, we need two more ingredients, **Fundamental Matrix (F)** and **Essential Matrix (E)**. Essential Matrix contains the information about translation and rotation, which describe the location of the second camera relative to the first in global coordinates. See the image below (Image courtesy: Learning OpenCV by Gary Bradsky): - - .. image:: images/essential_matrix.jpg - :alt: Essential Matrix - :align: center - -But we prefer measurements to be done in pixel coordinates, right? Fundamental Matrix contains the same information as Essential Matrix in addition to the information about the intrinsics of both cameras so that we can relate the two cameras in pixel coordinates. (If we are using rectified images and normalize the point by dividing by the focal lengths, :math:`F=E`). In simple words, Fundamental Matrix F, maps a point in one image to a line (epiline) in the other image. This is calculated from matching points from both the images. A minimum of 8 such points are required to find the fundamental matrix (while using 8-point algorithm). More points are preferred and use RANSAC to get a more robust result. - - -Code -========= - -So first we need to find as many possible matches between two images to find the fundamental matrix. For this, we use SIFT descriptors with FLANN based matcher and ratio test. -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img1 = cv2.imread('myleft.jpg',0) #queryimage # left image - img2 = cv2.imread('myright.jpg',0) #trainimage # right image - - sift = cv2.SIFT() - - # find the keypoints and descriptors with SIFT - kp1, des1 = sift.detectAndCompute(img1,None) - kp2, des2 = sift.detectAndCompute(img2,None) - - # FLANN parameters - FLANN_INDEX_KDTREE = 0 - index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) - search_params = dict(checks=50) - - flann = cv2.FlannBasedMatcher(index_params,search_params) - matches = flann.knnMatch(des1,des2,k=2) - - good = [] - pts1 = [] - pts2 = [] - - # ratio test as per Lowe's paper - for i,(m,n) in enumerate(matches): - if m.distance < 0.8*n.distance: - good.append(m) - pts2.append(kp2[m.trainIdx].pt) - pts1.append(kp1[m.queryIdx].pt) - - -Now we have the list of best matches from both the images. Let's find the Fundamental Matrix. -:: - - pts1 = np.int32(pts1) - pts2 = np.int32(pts2) - F, mask = cv2.findFundamentalMat(pts1,pts2,cv2.FM_LMEDS) - - # We select only inlier points - pts1 = pts1[mask.ravel()==1] - pts2 = pts2[mask.ravel()==1] - - -Next we find the epilines. Epilines corresponding to the points in first image is drawn on second image. So mentioning of correct images are important here. We get an array of lines. So we define a new function to draw these lines on the images. -:: - - def drawlines(img1,img2,lines,pts1,pts2): - ''' img1 - image on which we draw the epilines for the points in img2 - lines - corresponding epilines ''' - r,c = img1.shape - img1 = cv2.cvtColor(img1,cv2.COLOR_GRAY2BGR) - img2 = cv2.cvtColor(img2,cv2.COLOR_GRAY2BGR) - for r,pt1,pt2 in zip(lines,pts1,pts2): - color = tuple(np.random.randint(0,255,3).tolist()) - x0,y0 = map(int, [0, -r[2]/r[1] ]) - x1,y1 = map(int, [c, -(r[2]+r[0]*c)/r[1] ]) - img1 = cv2.line(img1, (x0,y0), (x1,y1), color,1) - img1 = cv2.circle(img1,tuple(pt1),5,color,-1) - img2 = cv2.circle(img2,tuple(pt2),5,color,-1) - return img1,img2 - - -Now we find the epilines in both the images and draw them. -:: - - # Find epilines corresponding to points in right image (second image) and - # drawing its lines on left image - lines1 = cv2.computeCorrespondEpilines(pts2.reshape(-1,1,2), 2,F) - lines1 = lines1.reshape(-1,3) - img5,img6 = drawlines(img1,img2,lines1,pts1,pts2) - - # Find epilines corresponding to points in left image (first image) and - # drawing its lines on right image - lines2 = cv2.computeCorrespondEpilines(pts1.reshape(-1,1,2), 1,F) - lines2 = lines2.reshape(-1,3) - img3,img4 = drawlines(img2,img1,lines2,pts2,pts1) - - plt.subplot(121),plt.imshow(img5) - plt.subplot(122),plt.imshow(img3) - plt.show() - - -Below is the result we get: - - .. image:: images/epiresult.jpg - :alt: Epilines - :align: center - - -You can see in the left image that all epilines are converging at a point outside the image at right side. That meeting point is the epipole. - -For better results, images with good resolution and many non-planar points should be used. - - -Additional Resources -========================== - - -Exercises -============= - -#. One important topic is the forward movement of camera. Then epipoles will be seen at the same locations in both with epilines emerging from a fixed point. `See this discussion `_. - -#. Fundamental Matrix estimation is sensitive to quality of matches, outliers etc. It becomes worse when all selected matches lie on the same plane. `Check this discussion `_. diff --git a/doc/py_tutorials/py_calib3d/py_pose/py_pose.rst b/doc/py_tutorials/py_calib3d/py_pose/py_pose.rst deleted file mode 100644 index c74380202d..0000000000 --- a/doc/py_tutorials/py_calib3d/py_pose/py_pose.rst +++ /dev/null @@ -1,132 +0,0 @@ -.. _pose_estimation: - - -Pose Estimation -********************* - -Goal -========== - -In this section, - * We will learn to exploit calib3d module to create some 3D effects in images. - - -Basics -======== - -This is going to be a small section. During the last session on camera calibration, you have found the camera matrix, distortion coefficients etc. Given a pattern image, we can utilize the above information to calculate its pose, or how the object is situated in space, like how it is rotated, how it is displaced etc. For a planar object, we can assume Z=0, such that, the problem now becomes how camera is placed in space to see our pattern image. So, if we know how the object lies in the space, we can draw some 2D diagrams in it to simulate the 3D effect. Let's see how to do it. - -Our problem is, we want to draw our 3D coordinate axis (X, Y, Z axes) on our chessboard's first corner. X axis in blue color, Y axis in green color and Z axis in red color. So in-effect, Z axis should feel like it is perpendicular to our chessboard plane. - -First, let's load the camera matrix and distortion coefficients from the previous calibration result. -:: - - import cv2 - import numpy as np - import glob - - # Load previously saved data - with np.load('B.npz') as X: - mtx, dist, _, _ = [X[i] for i in ('mtx','dist','rvecs','tvecs')] - - -Now let's create a function, ``draw`` which takes the corners in the chessboard (obtained using **cv2.findChessboardCorners()**) and **axis points** to draw a 3D axis. -:: - - def draw(img, corners, imgpts): - corner = tuple(corners[0].ravel()) - img = cv2.line(img, corner, tuple(imgpts[0].ravel()), (255,0,0), 5) - img = cv2.line(img, corner, tuple(imgpts[1].ravel()), (0,255,0), 5) - img = cv2.line(img, corner, tuple(imgpts[2].ravel()), (0,0,255), 5) - return img - -Then as in previous case, we create termination criteria, object points (3D points of corners in chessboard) and axis points. Axis points are points in 3D space for drawing the axis. We draw axis of length 3 (units will be in terms of chess square size since we calibrated based on that size). So our X axis is drawn from (0,0,0) to (3,0,0), so for Y axis. For Z axis, it is drawn from (0,0,0) to (0,0,-3). Negative denotes it is drawn towards the camera. -:: - - criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) - objp = np.zeros((6*7,3), np.float32) - objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2) - - axis = np.float32([[3,0,0], [0,3,0], [0,0,-3]]).reshape(-1,3) - - -Now, as usual, we load each image. Search for 7x6 grid. If found, we refine it with subcorner pixels. Then to calculate the rotation and translation, we use the function, **cv2.solvePnPRansac()**. Once we those transformation matrices, we use them to project our **axis points** to the image plane. In simple words, we find the points on image plane corresponding to each of (3,0,0),(0,3,0),(0,0,3) in 3D space. Once we get them, we draw lines from the first corner to each of these points using our ``draw()`` function. Done !!! - -:: - - for fname in glob.glob('left*.jpg'): - img = cv2.imread(fname) - gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - ret, corners = cv2.findChessboardCorners(gray, (7,6),None) - - if ret == True: - corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria) - - # Find the rotation and translation vectors. - rvecs, tvecs, inliers = cv2.solvePnPRansac(objp, corners2, mtx, dist) - - # project 3D points to image plane - imgpts, jac = cv2.projectPoints(axis, rvecs, tvecs, mtx, dist) - - img = draw(img,corners2,imgpts) - cv2.imshow('img',img) - k = cv2.waitKey(0) & 0xff - if k == 's': - cv2.imwrite(fname[:6]+'.png', img) - - cv2.destroyAllWindows() - -See some results below. Notice that each axis is 3 squares long.: - - .. image:: images/pose_1.jpg - :alt: Pose Estimation - :align: center - - -Render a Cube ---------------- - -If you want to draw a cube, modify the draw() function and axis points as follows. - -Modified draw() function: -:: - - def draw(img, corners, imgpts): - imgpts = np.int32(imgpts).reshape(-1,2) - - # draw ground floor in green - img = cv2.drawContours(img, [imgpts[:4]],-1,(0,255,0),-3) - - # draw pillars in blue color - for i,j in zip(range(4),range(4,8)): - img = cv2.line(img, tuple(imgpts[i]), tuple(imgpts[j]),(255),3) - - # draw top layer in red color - img = cv2.drawContours(img, [imgpts[4:]],-1,(0,0,255),3) - - return img - - -Modified axis points. They are the 8 corners of a cube in 3D space: -:: - - axis = np.float32([[0,0,0], [0,3,0], [3,3,0], [3,0,0], - [0,0,-3],[0,3,-3],[3,3,-3],[3,0,-3] ]) - - -And look at the result below: - - .. image:: images/pose_2.jpg - :alt: Pose Estimation - :align: center - - -If you are interested in graphics, augmented reality etc, you can use OpenGL to render more complicated figures. - - -Additional Resources -=========================== - - -Exercises -=========== diff --git a/doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/py_table_of_contents_calib3d.markdown b/doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d.markdown similarity index 100% rename from doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/py_table_of_contents_calib3d.markdown rename to doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d.markdown diff --git a/doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/py_table_of_contents_calib3d.rst b/doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/py_table_of_contents_calib3d.rst deleted file mode 100644 index 2dd3c94788..0000000000 --- a/doc/py_tutorials/py_calib3d/py_table_of_contents_calib3d/py_table_of_contents_calib3d.rst +++ /dev/null @@ -1,79 +0,0 @@ -.. _PY_Table-Of-Content-Calib: - - -Camera Calibration and 3D Reconstruction ----------------------------------------------- - -* :ref:`calibration` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |calib_1| Let's find how good is our camera. Is there any distortion in images taken with it? If so how to correct it? - - =========== ====================================================== - - .. |calib_1| image:: images/calibration_icon.jpg - :height: 90pt - :width: 90pt - - -* :ref:`pose_estimation` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |calib_2| This is a small section which will help you to create some cool 3D effects with calib module. - - =========== ====================================================== - - .. |calib_2| image:: images/pose_icon.jpg - :height: 90pt - :width: 90pt - - -* :ref:`epipolar_geometry` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |calib_3| Let's understand epipolar geometry and epipolar constraint. - - =========== ====================================================== - - .. |calib_3| image:: images/epipolar_icon.jpg - :height: 90pt - :width: 90pt - - -* :ref:`py_depthmap` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |calib_4| Extract depth information from 2D images. - - =========== ====================================================== - - .. |calib_4| image:: images/depthmap_icon.jpg - :height: 90pt - :width: 90pt - - - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_calibration/py_calibration - ../py_pose/py_pose - ../py_epipolar_geometry/py_epipolar_geometry - ../py_depthmap/py_depthmap diff --git a/doc/py_tutorials/py_core/py_table_of_contents_core/images/image_arithmetic.jpg b/doc/py_tutorials/py_core/images/image_arithmetic.jpg similarity index 100% rename from doc/py_tutorials/py_core/py_table_of_contents_core/images/image_arithmetic.jpg rename to doc/py_tutorials/py_core/images/image_arithmetic.jpg diff --git a/doc/py_tutorials/py_core/py_table_of_contents_core/images/maths_tools.jpg b/doc/py_tutorials/py_core/images/maths_tools.jpg similarity index 100% rename from doc/py_tutorials/py_core/py_table_of_contents_core/images/maths_tools.jpg rename to doc/py_tutorials/py_core/images/maths_tools.jpg diff --git a/doc/py_tutorials/py_core/py_table_of_contents_core/images/pixel_ops.jpg b/doc/py_tutorials/py_core/images/pixel_ops.jpg similarity index 100% rename from doc/py_tutorials/py_core/py_table_of_contents_core/images/pixel_ops.jpg rename to doc/py_tutorials/py_core/images/pixel_ops.jpg diff --git a/doc/py_tutorials/py_core/py_table_of_contents_core/images/speed.jpg b/doc/py_tutorials/py_core/images/speed.jpg similarity index 100% rename from doc/py_tutorials/py_core/py_table_of_contents_core/images/speed.jpg rename to doc/py_tutorials/py_core/images/speed.jpg diff --git a/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.rst b/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.rst deleted file mode 100644 index e4bbeff6d2..0000000000 --- a/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.rst +++ /dev/null @@ -1,181 +0,0 @@ -.. _Basic_Ops: - -Basic Operations on Images -****************************** - -Goal -======= - -Learn to: - - * Access pixel values and modify them - * Access image properties - * Setting Region of Image (ROI) - * Splitting and Merging images - - Almost all the operations in this section is mainly related to Numpy rather than OpenCV. A good knowledge of Numpy is required to write better optimized code with OpenCV. - - *( Examples will be shown in Python terminal since most of them are just single line codes )* - -Accessing and Modifying pixel values -======================================= - -Let's load a color image first: -:: - - >>> import cv2 - >>> import numpy as np - - >>> img = cv2.imread('messi5.jpg') - -You can access a pixel value by its row and column coordinates. For BGR image, it returns an array of Blue, Green, Red values. For grayscale image, just corresponding intensity is returned. -:: - - >>> px = img[100,100] - >>> print px - [157 166 200] - - # accessing only blue pixel - >>> blue = img[100,100,0] - >>> print blue - 157 - -You can modify the pixel values the same way. -:: - - >>> img[100,100] = [255,255,255] - >>> print img[100,100] - [255 255 255] - -.. warning:: Numpy is a optimized library for fast array calculations. So simply accessing each and every pixel values and modifying it will be very slow and it is discouraged. - -.. note:: Above mentioned method is normally used for selecting a region of array, say first 5 rows and last 3 columns like that. For individual pixel access, Numpy array methods, ``array.item()`` and ``array.itemset()`` is considered to be better. But it always returns a scalar. So if you want to access all B,G,R values, you need to call ``array.item()`` separately for all. - -Better pixel accessing and editing method : - -.. code-block:: python - - # accessing RED value - >>> img.item(10,10,2) - 59 - - # modifying RED value - >>> img.itemset((10,10,2),100) - >>> img.item(10,10,2) - 100 - -Accessing Image Properties -============================= - -Image properties include number of rows, columns and channels, type of image data, number of pixels etc. - -Shape of image is accessed by ``img.shape``. It returns a tuple of number of rows, columns and channels (if image is color): -:: - - >>> print img.shape - (342, 548, 3) - -.. note:: If image is grayscale, tuple returned contains only number of rows and columns. So it is a good method to check if loaded image is grayscale or color image. - -Total number of pixels is accessed by ``img.size``: -:: - - >>> print img.size - 562248 - -Image datatype is obtained by ``img.dtype``: -:: - - >>> print img.dtype - uint8 - -.. note:: ``img.dtype`` is very important while debugging because a large number of errors in OpenCV-Python code is caused by invalid datatype. - -Image ROI -=========== - -Sometimes, you will have to play with certain region of images. For eye detection in images, first face detection is done all over the image and when face is obtained, we select the face region alone and search for eyes inside it instead of searching whole image. It improves accuracy (because eyes are always on faces :D ) and performance (because we search for a small area) - -ROI is again obtained using Numpy indexing. Here I am selecting the ball and copying it to another region in the image: -:: - - >>> ball = img[280:340, 330:390] - >>> img[273:333, 100:160] = ball - -Check the results below: - - .. image:: images/roi.jpg - :alt: Image ROI - :align: center - -Splitting and Merging Image Channels -====================================== - -Sometimes you will need to work separately on B,G,R channels of image. Then you need to split the BGR images to single planes. Or another time, you may need to join these individual channels to BGR image. You can do it simply by: -:: - - >>> b,g,r = cv2.split(img) - >>> img = cv2.merge((b,g,r)) - -Or - - >>> b = img[:,:,0] - -Suppose, you want to make all the red pixels to zero, you need not split like this and put it equal to zero. You can simply use Numpy indexing, and that is more faster. -:: - - >>> img[:,:,2] = 0 - -.. warning:: ``cv2.split()`` is a costly operation (in terms of time). So do it only if you need it. Otherwise go for Numpy indexing. - -Making Borders for Images (Padding) -==================================== -If you want to create a border around the image, something like a photo frame, you can use **cv2.copyMakeBorder()** function. But it has more applications for convolution operation, zero padding etc. This function takes following arguments: - - * **src** - input image - * **top**, **bottom**, **left**, **right** - border width in number of pixels in corresponding directions - * **borderType** - Flag defining what kind of border to be added. It can be following types: - * **cv2.BORDER_CONSTANT** - Adds a constant colored border. The value should be given as next argument. - * **cv2.BORDER_REFLECT** - Border will be mirror reflection of the border elements, like this : *fedcba|abcdefgh|hgfedcb* - * **cv2.BORDER_REFLECT_101** or **cv2.BORDER_DEFAULT** - Same as above, but with a slight change, like this : *gfedcb|abcdefgh|gfedcba* - * **cv2.BORDER_REPLICATE** - Last element is replicated throughout, like this: *aaaaaa|abcdefgh|hhhhhhh* - * **cv2.BORDER_WRAP** - Can't explain, it will look like this : *cdefgh|abcdefgh|abcdefg* - * **value** - Color of border if border type is ``cv2.BORDER_CONSTANT`` - -Below is a sample code demonstrating all these border types for better understanding: -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - BLUE = [255,0,0] - - img1 = cv2.imread('opencv_logo.png') - - replicate = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REPLICATE) - reflect = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT) - reflect101 = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT_101) - wrap = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_WRAP) - constant= cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_CONSTANT,value=BLUE) - - plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL') - plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE') - plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT') - plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101') - plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP') - plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT') - - plt.show() - -See the result below. (Image is displayed with matplotlib. So RED and BLUE planes will be interchanged): - - .. image:: images/border.jpg - :alt: Border Types - :align: center - -Additional Resources -========================= - -Exercises -=========== diff --git a/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.rst b/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.rst deleted file mode 100644 index 0568fda44b..0000000000 --- a/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.rst +++ /dev/null @@ -1,115 +0,0 @@ -.. _Image_Arithmetics: - -Arithmetic Operations on Images -********************************* - -Goal -===== - - * Learn several arithmetic operations on images like addition, subtraction, bitwise operations etc. - * You will learn these functions : **cv2.add()**, **cv2.addWeighted()** etc. - -Image Addition -================ - -You can add two images by OpenCV function, ``cv2.add()`` or simply by numpy operation, ``res = img1 + img2``. Both images should be of same depth and type, or second image can just be a scalar value. - -.. note:: There is a difference between OpenCV addition and Numpy addition. OpenCV addition is a saturated operation while Numpy addition is a modulo operation. - -For example, consider below sample: -:: - - >>> x = np.uint8([250]) - >>> y = np.uint8([10]) - - >>> print cv2.add(x,y) # 250+10 = 260 => 255 - [[255]] - - >>> print x+y # 250+10 = 260 % 256 = 4 - [4] - -It will be more visible when you add two images. OpenCV function will provide a better result. So always better stick to OpenCV functions. - -Image Blending -================= - -This is also image addition, but different weights are given to images so that it gives a feeling of blending or transparency. Images are added as per the equation below: - -.. math:: - - g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x) - -By varying :math:`\alpha` from :math:`0 \rightarrow 1`, you can perform a cool transition between one image to another. - -Here I took two images to blend them together. First image is given a weight of 0.7 and second image is given 0.3. ``cv2.addWeighted()`` applies following equation on the image. - -.. math:: - - dst = \alpha \cdot img1 + \beta \cdot img2 + \gamma - -Here :math:`\gamma` is taken as zero. -:: - - img1 = cv2.imread('ml.png') - img2 = cv2.imread('opencv_logo.jpg') - - dst = cv2.addWeighted(img1,0.7,img2,0.3,0) - - cv2.imshow('dst',dst) - cv2.waitKey(0) - cv2.destroyAllWindows() - -Check the result below: - - .. image:: images/blending.jpg - :alt: Image Blending - :align: center - -Bitwise Operations -=================== - -This includes bitwise AND, OR, NOT and XOR operations. They will be highly useful while extracting any part of the image (as we will see in coming chapters), defining and working with non-rectangular ROI etc. Below we will see an example on how to change a particular region of an image. - -I want to put OpenCV logo above an image. If I add two images, it will change color. If I blend it, I get an transparent effect. But I want it to be opaque. If it was a rectangular region, I could use ROI as we did in last chapter. But OpenCV logo is a not a rectangular shape. So you can do it with bitwise operations as below: -:: - - # Load two images - img1 = cv2.imread('messi5.jpg') - img2 = cv2.imread('opencv_logo.png') - - # I want to put logo on top-left corner, So I create a ROI - rows,cols,channels = img2.shape - roi = img1[0:rows, 0:cols ] - - # Now create a mask of logo and create its inverse mask also - img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY) - ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY) - mask_inv = cv2.bitwise_not(mask) - - # Now black-out the area of logo in ROI - img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv) - - # Take only region of logo from logo image. - img2_fg = cv2.bitwise_and(img2,img2,mask = mask) - - # Put logo in ROI and modify the main image - dst = cv2.add(img1_bg,img2_fg) - img1[0:rows, 0:cols ] = dst - - cv2.imshow('res',img1) - cv2.waitKey(0) - cv2.destroyAllWindows() - -See the result below. Left image shows the mask we created. Right image shows the final result. For more understanding, display all the intermediate images in the above code, especially ``img1_bg`` and ``img2_fg``. - - .. image:: images/overlay.jpg - :alt: Otsu's Thresholding - :align: center - - -Additional Resources -====================== - -Exercises -============ -#. Create a slide show of images in a folder with smooth transition between images using ``cv2.addWeighted`` function diff --git a/doc/py_tutorials/py_core/py_maths_tools/py_maths_tools.rst b/doc/py_tutorials/py_core/py_maths_tools/py_maths_tools.rst deleted file mode 100644 index 0f30489e7f..0000000000 --- a/doc/py_tutorials/py_core/py_maths_tools/py_maths_tools.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. _Mathematical_Tools: - -Mathematical Tools in OpenCV -******************************** diff --git a/doc/py_tutorials/py_core/py_optimization/py_optimization.rst b/doc/py_tutorials/py_core/py_optimization/py_optimization.rst deleted file mode 100644 index 13160fd4d3..0000000000 --- a/doc/py_tutorials/py_core/py_optimization/py_optimization.rst +++ /dev/null @@ -1,141 +0,0 @@ -.. _Optimization_Techniques: - -Performance Measurement and Improvement Techniques -**************************************************** - -Goal -====== - -In image processing, since you are dealing with large number of operations per second, it is mandatory that your code is not only providing the correct solution, but also in the fastest manner. So in this chapter, you will learn - - * To measure the performance of your code. - * Some tips to improve the performance of your code. - * You will see these functions : **cv2.getTickCount**, **cv2.getTickFrequency** etc. - -Apart from OpenCV, Python also provides a module **time** which is helpful in measuring the time of execution. Another module **profile** helps to get detailed report on the code, like how much time each function in the code took, how many times the function was called etc. But, if you are using IPython, all these features are integrated in an user-friendly manner. We will see some important ones, and for more details, check links in **Additional Resouces** section. - -Measuring Performance with OpenCV -================================== - -**cv2.getTickCount** function returns the number of clock-cycles after a reference event (like the moment machine was switched ON) to the moment this function is called. So if you call it before and after the function execution, you get number of clock-cycles used to execute a function. - -**cv2.getTickFrequency** function returns the frequency of clock-cycles, or the number of clock-cycles per second. So to find the time of execution in seconds, you can do following: -:: - - e1 = cv2.getTickCount() - # your code execution - e2 = cv2.getTickCount() - time = (e2 - e1)/ cv2.getTickFrequency() - -We will demonstrate with following example. Following example apply median filtering with a kernel of odd size ranging from 5 to 49. (Don't worry about what will the result look like, that is not our goal): -:: - - img1 = cv2.imread('messi5.jpg') - - e1 = cv2.getTickCount() - for i in xrange(5,49,2): - img1 = cv2.medianBlur(img1,i) - e2 = cv2.getTickCount() - t = (e2 - e1)/cv2.getTickFrequency() - print t - - # Result I got is 0.521107655 seconds - -.. note:: You can do the same with ``time`` module. Instead of ``cv2.getTickCount``, use ``time.time()`` function. Then take the difference of two times. - - -Default Optimization in OpenCV -================================ - -Many of the OpenCV functions are optimized using SSE2, AVX etc. It contains unoptimized code also. So if our system support these features, we should exploit them (almost all modern day processors support them). It is enabled by default while compiling. So OpenCV runs the optimized code if it is enabled, else it runs the unoptimized code. You can use **cv2.useOptimized()** to check if it is enabled/disabled and **cv2.setUseOptimized()** to enable/disable it. Let's see a simple example. -:: - - # check if optimization is enabled - In [5]: cv2.useOptimized() - Out[5]: True - - In [6]: %timeit res = cv2.medianBlur(img,49) - 10 loops, best of 3: 34.9 ms per loop - - # Disable it - In [7]: cv2.setUseOptimized(False) - - In [8]: cv2.useOptimized() - Out[8]: False - - In [9]: %timeit res = cv2.medianBlur(img,49) - 10 loops, best of 3: 64.1 ms per loop - - -See, optimized median filtering is ~2x faster than unoptimized version. If you check its source, you can see median filtering is SIMD optimized. So you can use this to enable optimization at the top of your code (remember it is enabled by default). - - -Measuring Performance in IPython -============================================================ - -Sometimes you may need to compare the performance of two similar operations. IPython gives you a magic command ``%timeit`` to perform this. It runs the code several times to get more accurate results. Once again, they are suitable to measure single line codes. - -For example, do you know which of the following addition operation is better, ``x = 5; y = x**2``, ``x = 5; y = x*x``, ``x = np.uint8([5]); y = x*x`` or ``y = np.square(x)`` ? We will find it with %timeit in IPython shell. -:: - - In [10]: x = 5 - - In [11]: %timeit y=x**2 - 10000000 loops, best of 3: 73 ns per loop - - In [12]: %timeit y=x*x - 10000000 loops, best of 3: 58.3 ns per loop - - In [15]: z = np.uint8([5]) - - In [17]: %timeit y=z*z - 1000000 loops, best of 3: 1.25 us per loop - - In [19]: %timeit y=np.square(z) - 1000000 loops, best of 3: 1.16 us per loop - -You can see that, ``x = 5 ; y = x*x`` is fastest and it is around 20x faster compared to Numpy. If you consider the array creation also, it may reach upto 100x faster. Cool, right? *(Numpy devs are working on this issue)* - -.. note:: Python scalar operations are faster than Numpy scalar operations. So for operations including one or two elements, Python scalar is better than Numpy arrays. Numpy takes advantage when size of array is a little bit bigger. - -We will try one more example. This time, we will compare the performance of **cv2.countNonZero()** and **np.count_nonzero()** for same image. -:: - - In [35]: %timeit z = cv2.countNonZero(img) - 100000 loops, best of 3: 15.8 us per loop - - In [36]: %timeit z = np.count_nonzero(img) - 1000 loops, best of 3: 370 us per loop - -See, OpenCV function is nearly 25x faster than Numpy function. - -.. note:: Normally, OpenCV functions are faster than Numpy functions. So for same operation, OpenCV functions are preferred. But, there can be exceptions, especially when Numpy works with views instead of copies. - - -More IPython magic commands -============================= - -There are several other magic commands to measure the performance, profiling, line profiling, memory measurement etc. They all are well documented. So only links to those docs are provided here. Interested readers are recommended to try them out. - -Performance Optimization Techniques -===================================== - -There are several techniques and coding methods to exploit maximum performance of Python and Numpy. Only relevant ones are noted here and links are given to important sources. The main thing to be noted here is that, first try to implement the algorithm in a simple manner. Once it is working, profile it, find the bottlenecks and optimize them. - - #. Avoid using loops in Python as far as possible, especially double/triple loops etc. They are inherently slow. - #. Vectorize the algorithm/code to the maximum possible extent because Numpy and OpenCV are optimized for vector operations. - #. Exploit the cache coherence. - #. Never make copies of array unless it is needed. Try to use views instead. Array copying is a costly operation. - -Even after doing all these operations, if your code is still slow, or use of large loops are inevitable, use additional libraries like Cython to make it faster. - -Additional Resources -====================== - -1. `Python Optimization Techniques `_ -2. Scipy Lecture Notes - `Advanced Numpy `_ -3. `Timing and Profiling in IPython `_ - - -Exercises -============ diff --git a/doc/py_tutorials/py_core/py_table_of_contents_core/py_table_of_contents_core.markdown b/doc/py_tutorials/py_core/py_table_of_contents_core.markdown similarity index 100% rename from doc/py_tutorials/py_core/py_table_of_contents_core/py_table_of_contents_core.markdown rename to doc/py_tutorials/py_core/py_table_of_contents_core.markdown diff --git a/doc/py_tutorials/py_core/py_table_of_contents_core/py_table_of_contents_core.rst b/doc/py_tutorials/py_core/py_table_of_contents_core/py_table_of_contents_core.rst deleted file mode 100644 index 0cbbc2b033..0000000000 --- a/doc/py_tutorials/py_core/py_table_of_contents_core/py_table_of_contents_core.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. _PY_Table-Of-Content-Core: - -Core Operations ------------------------------------------------------------ - - -* :ref:`Basic_Ops` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |core_1| Learn to read and edit pixel values, working with image ROI and other basic operations. - - =========== ====================================================== - - .. |core_1| image:: images/pixel_ops.jpg - :height: 90pt - :width: 90pt - -* :ref:`Image_Arithmetics` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |core_2| Perform arithmetic operations on images - - =========== ====================================================== - - .. |core_2| image:: images/image_arithmetic.jpg - :height: 90pt - :width: 90pt - -* :ref:`Optimization_Techniques` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |core_4| Getting a solution is important. But getting it in the fastest way is more important. Learn to check the speed of your code, optimize the code etc. - - =========== ====================================================== - - .. |core_4| image:: images/speed.jpg - :height: 90pt - :width: 90pt - -* :ref:`Mathematical_Tools` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |core_5| Learn some of the mathematical tools provided by OpenCV like PCA, SVD etc. - - =========== ====================================================== - - .. |core_5| image:: images/maths_tools.jpg - :height: 90pt - :width: 90pt - - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_basic_ops/py_basic_ops - ../py_image_arithmetics/py_image_arithmetics - ../py_optimization/py_optimization - ../py_maths_tools/py_maths_tools diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/brief.jpg b/doc/py_tutorials/py_feature2d/images/brief.jpg similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/brief.jpg rename to doc/py_tutorials/py_feature2d/images/brief.jpg diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/fast_icon.jpg b/doc/py_tutorials/py_feature2d/images/fast_icon.jpg similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/fast_icon.jpg rename to doc/py_tutorials/py_feature2d/images/fast_icon.jpg diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/features_icon.jpg b/doc/py_tutorials/py_feature2d/images/features_icon.jpg similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/features_icon.jpg rename to doc/py_tutorials/py_feature2d/images/features_icon.jpg diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/harris_icon.jpg b/doc/py_tutorials/py_feature2d/images/harris_icon.jpg similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/harris_icon.jpg rename to doc/py_tutorials/py_feature2d/images/harris_icon.jpg diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/homography_icon.jpg b/doc/py_tutorials/py_feature2d/images/homography_icon.jpg similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/homography_icon.jpg rename to doc/py_tutorials/py_feature2d/images/homography_icon.jpg diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/matching.jpg b/doc/py_tutorials/py_feature2d/images/matching.jpg similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/matching.jpg rename to doc/py_tutorials/py_feature2d/images/matching.jpg diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/orb.jpg b/doc/py_tutorials/py_feature2d/images/orb.jpg similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/orb.jpg rename to doc/py_tutorials/py_feature2d/images/orb.jpg diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/shi_icon.jpg b/doc/py_tutorials/py_feature2d/images/shi_icon.jpg similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/shi_icon.jpg rename to doc/py_tutorials/py_feature2d/images/shi_icon.jpg diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/sift_icon.jpg b/doc/py_tutorials/py_feature2d/images/sift_icon.jpg similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/sift_icon.jpg rename to doc/py_tutorials/py_feature2d/images/sift_icon.jpg diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/surf_icon.jpg b/doc/py_tutorials/py_feature2d/images/surf_icon.jpg similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/images/surf_icon.jpg rename to doc/py_tutorials/py_feature2d/images/surf_icon.jpg diff --git a/doc/py_tutorials/py_feature2d/py_brief/py_brief.rst b/doc/py_tutorials/py_feature2d/py_brief/py_brief.rst deleted file mode 100644 index e179d9c6c2..0000000000 --- a/doc/py_tutorials/py_feature2d/py_brief/py_brief.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. _BRIEF: - - -BRIEF (Binary Robust Independent Elementary Features) -*********************************************************** - -Goal -======= -In this chapter - * We will see the basics of BRIEF algorithm - - -Theory -============= - -We know SIFT uses 128-dim vector for descriptors. Since it is using floating point numbers, it takes basically 512 bytes. Similarly SURF also takes minimum of 256 bytes (for 64-dim). Creating such a vector for thousands of features takes a lot of memory which are not feasible for resouce-constraint applications especially for embedded systems. Larger the memory, longer the time it takes for matching. - -But all these dimensions may not be needed for actual matching. We can compress it using several methods like PCA, LDA etc. Even other methods like hashing using LSH (Locality Sensitive Hashing) is used to convert these SIFT descriptors in floating point numbers to binary strings. These binary strings are used to match features using Hamming distance. This provides better speed-up because finding hamming distance is just applying XOR and bit count, which are very fast in modern CPUs with SSE instructions. But here, we need to find the descriptors first, then only we can apply hashing, which doesn't solve our initial problem on memory. - -BRIEF comes into picture at this moment. It provides a shortcut to find the binary strings directly without finding descriptors. It takes smoothened image patch and selects a set of :math:`n_d` (x,y) location pairs in an unique way (explained in paper). Then some pixel intensity comparisons are done on these location pairs. For eg, let first location pairs be :math:`p` and :math:`q`. If :math:`I(p) < I(q)`, then its result is 1, else it is 0. This is applied for all the :math:`n_d` location pairs to get a :math:`n_d`-dimensional bitstring. - -This :math:`n_d` can be 128, 256 or 512. OpenCV supports all of these, but by default, it would be 256 (OpenCV represents it in bytes. So the values will be 16, 32 and 64). So once you get this, you can use Hamming Distance to match these descriptors. - -One important point is that BRIEF is a feature descriptor, it doesn't provide any method to find the features. So you will have to use any other feature detectors like SIFT, SURF etc. The paper recommends to use CenSurE which is a fast detector and BRIEF works even slightly better for CenSurE points than for SURF points. - -In short, BRIEF is a faster method feature descriptor calculation and matching. It also provides high recognition rate unless there is large in-plane rotation. - -BRIEF in OpenCV -===================== - -Below code shows the computation of BRIEF descriptors with the help of CenSurE detector. (CenSurE detector is called STAR detector in OpenCV) -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img = cv2.imread('simple.jpg',0) - - # Initiate STAR detector - star = cv2.FeatureDetector_create("STAR") - - # Initiate BRIEF extractor - brief = cv2.DescriptorExtractor_create("BRIEF") - - # find the keypoints with STAR - kp = star.detect(img,None) - - # compute the descriptors with BRIEF - kp, des = brief.compute(img, kp) - - print brief.getInt('bytes') - print des.shape - -The function ``brief.getInt('bytes')`` gives the :math:`n_d` size used in bytes. By default it is 32. Next one is matching, which will be done in another chapter. - - -Additional Resources -========================== - -#. Michael Calonder, Vincent Lepetit, Christoph Strecha, and Pascal Fua, "BRIEF: Binary Robust Independent Elementary Features", 11th European Conference on Computer Vision (ECCV), Heraklion, Crete. LNCS Springer, September 2010. - -#. LSH (Locality Sensitive Hasing) at wikipedia. diff --git a/doc/py_tutorials/py_feature2d/py_fast/py_fast.rst b/doc/py_tutorials/py_feature2d/py_fast/py_fast.rst deleted file mode 100644 index eea0dae3b1..0000000000 --- a/doc/py_tutorials/py_feature2d/py_fast/py_fast.rst +++ /dev/null @@ -1,136 +0,0 @@ -.. _FAST: - -FAST Algorithm for Corner Detection -************************************* - -Goal -======= - -In this chapter, - * We will understand the basics of FAST algorithm - * We will find corners using OpenCV functionalities for FAST algorithm. - - -Theory -========= - -We saw several feature detectors and many of them are really good. But when looking from a real-time application point of view, they are not fast enough. One best example would be SLAM (Simultaneous Localization and Mapping) mobile robot which have limited computational resources. - -As a solution to this, FAST (Features from Accelerated Segment Test) algorithm was proposed by Edward Rosten and Tom Drummond in their paper "Machine learning for high-speed corner detection" in 2006 (Later revised it in 2010). A basic summary of the algorithm is presented below. Refer original paper for more details (All the images are taken from original paper). - - -Feature Detection using FAST ------------------------------- - -1. Select a pixel :math:`p` in the image which is to be identified as an interest point or not. Let its intensity be :math:`I_p`. -2. Select appropriate threshold value :math:`t`. -3. Consider a circle of 16 pixels around the pixel under test. (See the image below) - - .. image:: images/fast_speedtest.jpg - :alt: A corner in the image - :align: center - -4. Now the pixel :math:`p` is a corner if there exists a set of :math:`n` contiguous pixels in the circle (of 16 pixels) which are all brighter than :math:`I_p + t`, or all darker than :math:`I_p − t`. (Shown as white dash lines in the above image). :math:`n` was chosen to be 12. -5. A **high-speed test** was proposed to exclude a large number of non-corners. This test examines only the four pixels at 1, 9, 5 and 13 (First 1 and 9 are tested if they are too brighter or darker. If so, then checks 5 and 13). If :math:`p` is a corner, then at least three of these must all be brighter than :math:`I_p + t` or darker than :math:`I_p − t`. If neither of these is the case, then :math:`p` cannot be a corner. The full segment test criterion can then be applied to the passed candidates by examining all pixels in the circle. This detector in itself exhibits high performance, but there are several weaknesses: - - * It does not reject as many candidates for n < 12. - * The choice of pixels is not optimal because its efficiency depends on ordering of the questions and distribution of corner appearances. - * Results of high-speed tests are thrown away. - * Multiple features are detected adjacent to one another. - -First 3 points are addressed with a machine learning approach. Last one is addressed using non-maximal suppression. - - -Machine Learning a Corner Detector ------------------------------------- - -1. Select a set of images for training (preferably from the target application domain) -2. Run FAST algorithm in every images to find feature points. -3. For every feature point, store the 16 pixels around it as a vector. Do it for all the images to get feature vector :math:`P`. -4. Each pixel (say :math:`x`) in these 16 pixels can have one of the following three states: - - .. image:: images/fast_eqns.jpg - :alt: FAST equation - :align: center - -5. Depending on these states, the feature vector :math:`P` is subdivided into 3 subsets, :math:`P_d`, :math:`P_s`, :math:`P_b`. -6. Define a new boolean variable, :math:`K_p`, which is true if :math:`p` is a corner and false otherwise. -7. Use the ID3 algorithm (decision tree classifier) to query each subset using the variable :math:`K_p` for the knowledge about the true class. It selects the :math:`x` which yields the most information about whether the candidate pixel is a corner, measured by the entropy of :math:`K_p`. -8. This is recursively applied to all the subsets until its entropy is zero. -9. The decision tree so created is used for fast detection in other images. - - -Non-maximal Suppression ---------------------------- - -Detecting multiple interest points in adjacent locations is another problem. It is solved by using Non-maximum Suppression. - -1. Compute a score function, :math:`V` for all the detected feature points. :math:`V` is the sum of absolute difference between :math:`p` and 16 surrounding pixels values. -2. Consider two adjacent keypoints and compute their :math:`V` values. -3. Discard the one with lower :math:`V` value. - - -Summary ------------ - -It is several times faster than other existing corner detectors. - -But it is not robust to high levels of noise. It is dependant on a threshold. - - -FAST Feature Detector in OpenCV -================================== - -It is called as any other feature detector in OpenCV. If you want, you can specify the threshold, whether non-maximum suppression to be applied or not, the neighborhood to be used etc. - -For the neighborhood, three flags are defined, ``cv2.FAST_FEATURE_DETECTOR_TYPE_5_8``, ``cv2.FAST_FEATURE_DETECTOR_TYPE_7_12`` and ``cv2.FAST_FEATURE_DETECTOR_TYPE_9_16``. Below is a simple code on how to detect and draw the FAST feature points. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img = cv2.imread('simple.jpg',0) - - # Initiate FAST object with default values - fast = cv2.FastFeatureDetector() - - # find and draw the keypoints - kp = fast.detect(img,None) - img2 = cv2.drawKeypoints(img, kp, color=(255,0,0)) - - # Print all default params - print "Threshold: ", fast.getInt('threshold') - print "nonmaxSuppression: ", fast.getBool('nonmaxSuppression') - print "neighborhood: ", fast.getInt('type') - print "Total Keypoints with nonmaxSuppression: ", len(kp) - - cv2.imwrite('fast_true.png',img2) - - # Disable nonmaxSuppression - fast.setBool('nonmaxSuppression',0) - kp = fast.detect(img,None) - - print "Total Keypoints without nonmaxSuppression: ", len(kp) - - img3 = cv2.drawKeypoints(img, kp, color=(255,0,0)) - - cv2.imwrite('fast_false.png',img3) - -See the results. First image shows FAST with nonmaxSuppression and second one without nonmaxSuppression: - - .. image:: images/fast_kp.jpg - :alt: FAST Keypoints - :align: center - - -Additional Resources -========================= - -#. Edward Rosten and Tom Drummond, “Machine learning for high speed corner detection†in 9th European Conference on Computer Vision, vol. 1, 2006, pp. 430–443. - -#. Edward Rosten, Reid Porter, and Tom Drummond, "Faster and better: a machine learning approach to corner detection" in IEEE Trans. Pattern Analysis and Machine Intelligence, 2010, vol 32, pp. 105-119. - - -Exercises -============ diff --git a/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.rst b/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.rst deleted file mode 100644 index f69ce4009a..0000000000 --- a/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.rst +++ /dev/null @@ -1,110 +0,0 @@ -.. _PY_feature_homography: - - -Feature Matching + Homography to find Objects -*********************************************** - -Goal -====== -In this chapter, - * We will mix up the feature matching and findHomography from calib3d module to find known objects in a complex image. - - -Basics -========= - -So what we did in last session? We used a queryImage, found some feature points in it, we took another trainImage, found the features in that image too and we found the best matches among them. In short, we found locations of some parts of an object in another cluttered image. This information is sufficient to find the object exactly on the trainImage. - -For that, we can use a function from calib3d module, ie **cv2.findHomography()**. If we pass the set of points from both the images, it will find the perpective transformation of that object. Then we can use **cv2.perspectiveTransform()** to find the object. It needs atleast four correct points to find the transformation. - -We have seen that there can be some possible errors while matching which may affect the result. To solve this problem, algorithm uses RANSAC or LEAST_MEDIAN (which can be decided by the flags). So good matches which provide correct estimation are called inliers and remaining are called outliers. **cv2.findHomography()** returns a mask which specifies the inlier and outlier points. - -So let's do it !!! - - -Code -========= - -First, as usual, let's find SIFT features in images and apply the ratio test to find the best matches. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - MIN_MATCH_COUNT = 10 - - img1 = cv2.imread('box.png',0) # queryImage - img2 = cv2.imread('box_in_scene.png',0) # trainImage - - # Initiate SIFT detector - sift = cv2.SIFT() - - # find the keypoints and descriptors with SIFT - kp1, des1 = sift.detectAndCompute(img1,None) - kp2, des2 = sift.detectAndCompute(img2,None) - - FLANN_INDEX_KDTREE = 0 - index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) - search_params = dict(checks = 50) - - flann = cv2.FlannBasedMatcher(index_params, search_params) - - matches = flann.knnMatch(des1,des2,k=2) - - # store all the good matches as per Lowe's ratio test. - good = [] - for m,n in matches: - if m.distance < 0.7*n.distance: - good.append(m) - - -Now we set a condition that atleast 10 matches (defined by MIN_MATCH_COUNT) are to be there to find the object. Otherwise simply show a message saying not enough matches are present. - -If enough matches are found, we extract the locations of matched keypoints in both the images. They are passed to find the perpective transformation. Once we get this 3x3 transformation matrix, we use it to transform the corners of queryImage to corresponding points in trainImage. Then we draw it. -:: - - if len(good)>MIN_MATCH_COUNT: - src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2) - dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2) - - M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0) - matchesMask = mask.ravel().tolist() - - h,w = img1.shape - pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2) - dst = cv2.perspectiveTransform(pts,M) - - img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA) - - else: - print "Not enough matches are found - %d/%d" % (len(good),MIN_MATCH_COUNT) - matchesMask = None - - -Finally we draw our inliers (if successfully found the object) or matching keypoints (if failed). -:: - - draw_params = dict(matchColor = (0,255,0), # draw matches in green color - singlePointColor = None, - matchesMask = matchesMask, # draw only inliers - flags = 2) - - img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params) - - plt.imshow(img3, 'gray'),plt.show() - - -See the result below. Object is marked in white color in cluttered image: - - .. image:: images/homography_findobj.jpg - :alt: Finding object with feature homography - :align: center - - -Additional Resources -============================ - - -Exercises -================== diff --git a/doc/py_tutorials/py_feature2d/py_features_harris/py_features_harris.rst b/doc/py_tutorials/py_feature2d/py_features_harris/py_features_harris.rst deleted file mode 100644 index b8a24a072c..0000000000 --- a/doc/py_tutorials/py_feature2d/py_features_harris/py_features_harris.rst +++ /dev/null @@ -1,154 +0,0 @@ -.. _Harris_Corners: - -Harris Corner Detection -**************************** - -Goal -======= - -In this chapter, - - * We will understand the concepts behind Harris Corner Detection. - * We will see the functions: **cv2.cornerHarris()**, **cv2.cornerSubPix()** - -Theory -========== - -In last chapter, we saw that corners are regions in the image with large variation in intensity in all the directions. One early attempt to find these corners was done by **Chris Harris & Mike Stephens** in their paper **A Combined Corner and Edge Detector** in 1988, so now it is called Harris Corner Detector. He took this simple idea to a mathematical form. It basically finds the difference in intensity for a displacement of :math:`(u,v)` in all directions. This is expressed as below: - -.. math:: - - E(u,v) = \sum_{x,y} \underbrace{w(x,y)}_\text{window function} \, [\underbrace{I(x+u,y+v)}_\text{shifted intensity}-\underbrace{I(x,y)}_\text{intensity}]^2 - -Window function is either a rectangular window or gaussian window which gives weights to pixels underneath. - -We have to maximize this function :math:`E(u,v)` for corner detection. That means, we have to maximize the second term. Applying Taylor Expansion to above equation and using some mathematical steps (please refer any standard text books you like for full derivation), we get the final equation as: - -.. math:: - - E(u,v) \approx \begin{bmatrix} u & v \end{bmatrix} M \begin{bmatrix} u \\ v \end{bmatrix} - -where - -.. math:: - - M = \sum_{x,y} w(x,y) \begin{bmatrix}I_x I_x & I_x I_y \\ - I_x I_y & I_y I_y \end{bmatrix} - -Here, :math:`I_x` and :math:`I_y` are image derivatives in x and y directions respectively. (Can be easily found out using **cv2.Sobel()**). - -Then comes the main part. After this, they created a score, basically an equation, which will determine if a window can contain a corner or not. - -.. math:: - - R = det(M) - k(trace(M))^2 - -where - * :math:`det(M) = \lambda_1 \lambda_2` - * :math:`trace(M) = \lambda_1 + \lambda_2` - * :math:`\lambda_1` and :math:`\lambda_2` are the eigen values of M - -So the values of these eigen values decide whether a region is corner, edge or flat. - - * When :math:`|R|` is small, which happens when :math:`\lambda_1` and :math:`\lambda_2` are small, the region is flat. - * When :math:`R<0`, which happens when :math:`\lambda_1 >> \lambda_2` or vice versa, the region is edge. - * When :math:`R` is large, which happens when :math:`\lambda_1` and :math:`\lambda_2` are large and :math:`\lambda_1 \sim \lambda_2`, the region is a corner. - -It can be represented in a nice picture as follows: - - .. image:: images/harris_region.jpg - :alt: Classification of Image Points - :align: center - -So the result of Harris Corner Detection is a grayscale image with these scores. Thresholding for a suitable give you the corners in the image. We will do it with a simple image. - - -Harris Corner Detector in OpenCV -==================================== - -OpenCV has the function **cv2.cornerHarris()** for this purpose. Its arguments are : - - * **img** - Input image, it should be grayscale and float32 type. - * **blockSize** - It is the size of neighbourhood considered for corner detection - * **ksize** - Aperture parameter of Sobel derivative used. - * **k** - Harris detector free parameter in the equation. - -See the example below: -:: - - import cv2 - import numpy as np - - filename = 'chessboard.jpg' - img = cv2.imread(filename) - gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - - gray = np.float32(gray) - dst = cv2.cornerHarris(gray,2,3,0.04) - - #result is dilated for marking the corners, not important - dst = cv2.dilate(dst,None) - - # Threshold for an optimal value, it may vary depending on the image. - img[dst>0.01*dst.max()]=[0,0,255] - - cv2.imshow('dst',img) - if cv2.waitKey(0) & 0xff == 27: - cv2.destroyAllWindows() - - -Below are the three results: - - .. image:: images/harris_result.jpg - :alt: Harris Corner Detection - :align: center - - -Corner with SubPixel Accuracy -=============================== - -Sometimes, you may need to find the corners with maximum accuracy. OpenCV comes with a function **cv2.cornerSubPix()** which further refines the corners detected with sub-pixel accuracy. Below is an example. As usual, we need to find the harris corners first. Then we pass the centroids of these corners (There may be a bunch of pixels at a corner, we take their centroid) to refine them. Harris corners are marked in red pixels and refined corners are marked in green pixels. For this function, we have to define the criteria when to stop the iteration. We stop it after a specified number of iteration or a certain accuracy is achieved, whichever occurs first. We also need to define the size of neighbourhood it would search for corners. -:: - - import cv2 - import numpy as np - - filename = 'chessboard2.jpg' - img = cv2.imread(filename) - gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - - # find Harris corners - gray = np.float32(gray) - dst = cv2.cornerHarris(gray,2,3,0.04) - dst = cv2.dilate(dst,None) - ret, dst = cv2.threshold(dst,0.01*dst.max(),255,0) - dst = np.uint8(dst) - - # find centroids - ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst) - - # define the criteria to stop and refine the corners - criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001) - corners = cv2.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria) - - # Now draw them - res = np.hstack((centroids,corners)) - res = np.int0(res) - img[res[:,1],res[:,0]]=[0,0,255] - img[res[:,3],res[:,2]] = [0,255,0] - - cv2.imwrite('subpixel5.png',img) - -Below is the result, where some important locations are shown in zoomed window to visualize: - - .. image:: images/subpixel3.png - :alt: Corner Detection with SubPixel Accuracy - :align: center - - -Additional Resources -====================== - - -Exercises -============ diff --git a/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.rst b/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.rst deleted file mode 100644 index d81fbc8052..0000000000 --- a/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. _Features_Meaning: - -Understanding Features -************************ - -Goal -===== - -In this chapter, we will just try to understand what are features, why are they important, why corners are important etc. - -Explanation -============== - -Most of you will have played the jigsaw puzzle games. You get a lot of small pieces of a images, where you need to assemble them correctly to form a big real image. **The question is, how you do it?** What about the projecting the same theory to a computer program so that computer can play jigsaw puzzles? If the computer can play jigsaw puzzles, why can't we give a lot of real-life images of a good natural scenery to computer and tell it to stitch all those images to a big single image? If the computer can stitch several natural images to one, what about giving a lot of pictures of a building or any structure and tell computer to create a 3D model out of it? - -Well, the questions and imaginations continue. But it all depends on the most basic question: How do you play jigsaw puzzles? How do you arrange lots of scrambled image pieces into a big single image? How can you stitch a lot of natural images to a single image? - -The answer is, we are looking for specific patterns or specific features which are unique, which can be easily tracked, which can be easily compared. If we go for a definition of such a feature, we may find it difficult to express it in words, but we know what are they. If some one asks you to point out one good feature which can be compared across several images, you can point out one. That is why, even small children can simply play these games. We search for these features in an image, we find them, we find the same features in other images, we align them. That's it. (In jigsaw puzzle, we look more into continuity of different images). All these abilities are present in us inherently. - -So our one basic question expands to more in number, but becomes more specific. **What are these features?**. *(The answer should be understandable to a computer also.)* - -Well, it is difficult to say how humans find these features. It is already programmed in our brain. But if we look deep into some pictures and search for different patterns, we will find something interesting. For example, take below image: - - .. image:: images/feature_building.jpg - :alt: Understanding features - :align: center - -Image is very simple. At the top of image, six small image patches are given. Question for you is to find the exact location of these patches in the original image. How many correct results you can find ? - -A and B are flat surfaces, and they are spread in a lot of area. It is difficult to find the exact location of these patches. - -C and D are much more simpler. They are edges of the building. You can find an approximate location, but exact location is still difficult. It is because, along the edge, it is same everywhere. Normal to the edge, it is different. So edge is a much better feature compared to flat area, but not good enough (It is good in jigsaw puzzle for comparing continuity of edges). - -Finally, E and F are some corners of the building. And they can be easily found out. Because at corners, wherever you move this patch, it will look different. So they can be considered as a good feature. So now we move into more simpler (and widely used image) for better understanding. - - .. image:: images/feature_simple.png - :alt: Features - :align: center - -Just like above, blue patch is flat area and difficult to find and track. Wherever you move the blue patch, it looks the same. For black patch, it is an edge. If you move it in vertical direction (i.e. along the gradient) it changes. Put along the edge (parallel to edge), it looks the same. And for red patch, it is a corner. Wherever you move the patch, it looks different, means it is unique. So basically, corners are considered to be good features in an image. (Not just corners, in some cases blobs are considered good features). - -So now we answered our question, "what are these features?". But next question arises. How do we find them? Or how do we find the corners?. That also we answered in an intuitive way, i.e., look for the regions in images which have maximum variation when moved (by a small amount) in all regions around it. This would be projected into computer language in coming chapters. So finding these image features is called **Feature Detection**. - -So we found the features in image (Assume you did it). Once you found it, you should find the same in the other images. What we do? We take a region around the feature, we explain it in our own words, like "upper part is blue sky, lower part is building region, on that building there are some glasses etc" and you search for the same area in other images. Basically, you are describing the feature. Similar way, computer also should describe the region around the feature so that it can find it in other images. So called description is called **Feature Description**. Once you have the features and its description, you can find same features in all images and align them, stitch them or do whatever you want. - -So in this module, we are looking to different algorithms in OpenCV to find features, describe them, match them etc. - -Additional Resources -======================= - -Exercises -=========== diff --git a/doc/py_tutorials/py_feature2d/py_matcher/py_matcher.rst b/doc/py_tutorials/py_feature2d/py_matcher/py_matcher.rst deleted file mode 100644 index 986facc848..0000000000 --- a/doc/py_tutorials/py_feature2d/py_matcher/py_matcher.rst +++ /dev/null @@ -1,207 +0,0 @@ -.. _Matcher: - - -Feature Matching -********************************************* - -Goal -===== -In this chapter - * We will see how to match features in one image with others. - * We will use the Brute-Force matcher and FLANN Matcher in OpenCV - - -Basics of Brute-Force Matcher -=================================== - -Brute-Force matcher is simple. It takes the descriptor of one feature in first set and is matched with all other features in second set using some distance calculation. And the closest one is returned. - -For BF matcher, first we have to create the BFMatcher object using **cv2.BFMatcher()**. It takes two optional params. First one is ``normType``. It specifies the distance measurement to be used. By default, it is ``cv2.NORM_L2``. It is good for SIFT, SURF etc (``cv2.NORM_L1`` is also there). For binary string based descriptors like ORB, BRIEF, BRISK etc, ``cv2.NORM_HAMMING`` should be used, which used Hamming distance as measurement. If ORB is using ``WTA_K == 3 or 4``, ``cv2.NORM_HAMMING2`` should be used. - -Second param is boolean variable, ``crossCheck`` which is false by default. If it is true, Matcher returns only those matches with value (i,j) such that i-th descriptor in set A has j-th descriptor in set B as the best match and vice-versa. That is, the two features in both sets should match each other. It provides consistant result, and is a good alternative to ratio test proposed by D.Lowe in SIFT paper. - -Once it is created, two important methods are *BFMatcher.match()* and *BFMatcher.knnMatch()*. First one returns the best match. Second method returns `k` best matches where k is specified by the user. It may be useful when we need to do additional work on that. - -Like we used cv2.drawKeypoints() to draw keypoints, **cv2.drawMatches()** helps us to draw the matches. It stacks two images horizontally and draw lines from first image to second image showing best matches. There is also **cv2.drawMatchesKnn** which draws all the k best matches. If k=2, it will draw two match-lines for each keypoint. So we have to pass a mask if we want to selectively draw it. - -Let's see one example for each of SURF and ORB (Both use different distance measurements). - - - -Brute-Force Matching with ORB Descriptors --------------------------------------------- - -Here, we will see a simple example on how to match features between two images. In this case, I have a queryImage and a trainImage. We will try to find the queryImage in trainImage using feature matching. ( The images are ``/samples/c/box.png`` and ``/samples/c/box_in_scene.png``) - -We are using SIFT descriptors to match features. So let's start with loading images, finding descriptors etc. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img1 = cv2.imread('box.png',0) # queryImage - img2 = cv2.imread('box_in_scene.png',0) # trainImage - - # Initiate SIFT detector - orb = cv2.ORB() - - # find the keypoints and descriptors with SIFT - kp1, des1 = orb.detectAndCompute(img1,None) - kp2, des2 = orb.detectAndCompute(img2,None) - - -Next we create a BFMatcher object with distance measurement ``cv2.NORM_HAMMING`` (since we are using ORB) and ``crossCheck`` is switched on for better results. Then we use Matcher.match() method to get the best matches in two images. We sort them in ascending order of their distances so that best matches (with low distance) come to front. Then we draw only first 10 matches (Just for sake of visibility. You can increase it as you like) -:: - - # create BFMatcher object - bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) - - # Match descriptors. - matches = bf.match(des1,des2) - - # Sort them in the order of their distance. - matches = sorted(matches, key = lambda x:x.distance) - - # Draw first 10 matches. - img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], flags=2) - - plt.imshow(img3),plt.show() - -Below is the result I got: - - .. image:: images/matcher_result1.jpg - :alt: ORB Feature Matching with Brute-Force - :align: center - - -What is this Matcher Object? ------------------------------------ - -The result of ``matches = bf.match(des1,des2)`` line is a list of DMatch objects. This DMatch object has following attributes: - - * ``DMatch.distance`` - Distance between descriptors. The lower, the better it is. - * ``DMatch.trainIdx`` - Index of the descriptor in train descriptors - * ``DMatch.queryIdx`` - Index of the descriptor in query descriptors - * ``DMatch.imgIdx`` - Index of the train image. - - -Brute-Force Matching with SIFT Descriptors and Ratio Test -------------------------------------------------------------- - -This time, we will use ``BFMatcher.knnMatch()`` to get k best matches. In this example, we will take k=2 so that we can apply ratio test explained by D.Lowe in his paper. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img1 = cv2.imread('box.png',0) # queryImage - img2 = cv2.imread('box_in_scene.png',0) # trainImage - - # Initiate SIFT detector - sift = cv2.SIFT() - - # find the keypoints and descriptors with SIFT - kp1, des1 = sift.detectAndCompute(img1,None) - kp2, des2 = sift.detectAndCompute(img2,None) - - # BFMatcher with default params - bf = cv2.BFMatcher() - matches = bf.knnMatch(des1,des2, k=2) - - # Apply ratio test - good = [] - for m,n in matches: - if m.distance < 0.75*n.distance: - good.append([m]) - - # cv2.drawMatchesKnn expects list of lists as matches. - img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,flags=2) - - plt.imshow(img3),plt.show() - -See the result below: - - .. image:: images/matcher_result2.jpg - :alt: SIFT Descriptor with ratio test - :align: center - - -FLANN based Matcher -========================== - -FLANN stands for Fast Library for Approximate Nearest Neighbors. It contains a collection of algorithms optimized for fast nearest neighbor search in large datasets and for high dimensional features. It works more faster than BFMatcher for large datasets. We will see the second example with FLANN based matcher. - -For FLANN based matcher, we need to pass two dictionaries which specifies the algorithm to be used, its related parameters etc. First one is IndexParams. For various algorithms, the information to be passed is explained in FLANN docs. As a summary, for algorithms like SIFT, SURF etc. you can pass following: -:: - - index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) - -While using ORB, you can pass the following. The commented values are recommended as per the docs, but it didn't provide required results in some cases. Other values worked fine.: -:: - - index_params= dict(algorithm = FLANN_INDEX_LSH, - table_number = 6, # 12 - key_size = 12, # 20 - multi_probe_level = 1) #2 - -Second dictionary is the SearchParams. It specifies the number of times the trees in the index should be recursively traversed. Higher values gives better precision, but also takes more time. If you want to change the value, pass ``search_params = dict(checks=100)``. - -With these informations, we are good to go. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img1 = cv2.imread('box.png',0) # queryImage - img2 = cv2.imread('box_in_scene.png',0) # trainImage - - # Initiate SIFT detector - sift = cv2.SIFT() - - # find the keypoints and descriptors with SIFT - kp1, des1 = sift.detectAndCompute(img1,None) - kp2, des2 = sift.detectAndCompute(img2,None) - - # FLANN parameters - FLANN_INDEX_KDTREE = 0 - index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) - search_params = dict(checks=50) # or pass empty dictionary - - flann = cv2.FlannBasedMatcher(index_params,search_params) - - matches = flann.knnMatch(des1,des2,k=2) - - # Need to draw only good matches, so create a mask - matchesMask = [[0,0] for i in xrange(len(matches))] - - # ratio test as per Lowe's paper - for i,(m,n) in enumerate(matches): - if m.distance < 0.7*n.distance: - matchesMask[i]=[1,0] - - draw_params = dict(matchColor = (0,255,0), - singlePointColor = (255,0,0), - matchesMask = matchesMask, - flags = 0) - - img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params) - - plt.imshow(img3,),plt.show() - - -See the result below: - - .. image:: images/matcher_flann.jpg - :alt: FLANN based matching - :align: center - - -Additional Resources -======================== - - -Exercises -================= diff --git a/doc/py_tutorials/py_feature2d/py_orb/py_orb.rst b/doc/py_tutorials/py_feature2d/py_orb/py_orb.rst deleted file mode 100644 index ee94c5a032..0000000000 --- a/doc/py_tutorials/py_feature2d/py_orb/py_orb.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. _ORB: - -ORB (Oriented FAST and Rotated BRIEF) -*************************************** - -Goal -====== - -In this chapter, - * We will see the basics of ORB - - -Theory -========== - -As an OpenCV enthusiast, the most important thing about the ORB is that it came from "OpenCV Labs". This algorithm was brought up by Ethan Rublee, Vincent Rabaud, Kurt Konolige and Gary R. Bradski in their paper **ORB: An efficient alternative to SIFT or SURF** in 2011. As the title says, it is a good alternative to SIFT and SURF in computation cost, matching performance and mainly the patents. Yes, SIFT and SURF are patented and you are supposed to pay them for its use. But ORB is not !!! - -ORB is basically a fusion of FAST keypoint detector and BRIEF descriptor with many modifications to enhance the performance. First it use FAST to find keypoints, then apply Harris corner measure to find top N points among them. It also use pyramid to produce multiscale-features. But one problem is that, FAST doesn't compute the orientation. So what about rotation invariance? Authors came up with following modification. - -It computes the intensity weighted centroid of the patch with located corner at center. The direction of the vector from this corner point to centroid gives the orientation. To improve the rotation invariance, moments are computed with x and y which should be in a circular region of radius :math:`r`, where :math:`r` is the size of the patch. - -Now for descriptors, ORB use BRIEF descriptors. But we have already seen that BRIEF performs poorly with rotation. So what ORB does is to "steer" BRIEF according to the orientation of keypoints. For any feature set of :math:`n` binary tests at location -:math:`(x_i, y_i)`, define a :math:`2 \times n` matrix, :math:`S` which contains the coordinates of these pixels. Then using the orientation of patch, :math:`\theta`, its rotation matrix is found and rotates the :math:`S` to get steered(rotated) version :math:`S_\theta`. - -ORB discretize the angle to increments of :math:`2 \pi /30` (12 degrees), and construct a lookup table of precomputed BRIEF patterns. As long as the keypoint orientation :math:`\theta` is consistent across views, the correct set of points :math:`S_\theta` will be used to compute its descriptor. - -BRIEF has an important property that each bit feature has a large variance and a mean near 0.5. But once it is oriented along keypoint direction, it loses this property and become more distributed. High variance makes a feature more discriminative, since it responds differentially to inputs. Another desirable property is to have the tests uncorrelated, since then each test will contribute to the result. To resolve all these, ORB runs a greedy search among all possible binary tests to find the ones that have both high variance and means close to 0.5, as well as being uncorrelated. The result is called **rBRIEF**. - -For descriptor matching, multi-probe LSH which improves on the traditional LSH, is used. The paper says ORB is much faster than SURF and SIFT and ORB descriptor works better than SURF. ORB is a good choice in low-power devices for panorama stitching etc. - - -ORB in OpenCV -================ - -As usual, we have to create an ORB object with the function, **cv2.ORB()** or using feature2d common interface. It has a number of optional parameters. Most useful ones are ``nFeatures`` which denotes maximum number of features to be retained (by default 500), ``scoreType`` which denotes whether Harris score or FAST score to rank the features (by default, Harris score) etc. Another parameter, ``WTA_K`` decides number of points that produce each element of the oriented BRIEF descriptor. By default it is two, ie selects two points at a time. In that case, for matching, ``NORM_HAMMING`` distance is used. If WTA_K is 3 or 4, which takes 3 or 4 points to produce BRIEF descriptor, then matching distance is defined by ``NORM_HAMMING2``. - -Below is a simple code which shows the use of ORB. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img = cv2.imread('simple.jpg',0) - - # Initiate STAR detector - orb = cv2.ORB() - - # find the keypoints with ORB - kp = orb.detect(img,None) - - # compute the descriptors with ORB - kp, des = orb.compute(img, kp) - - # draw only keypoints location,not size and orientation - img2 = cv2.drawKeypoints(img,kp,color=(0,255,0), flags=0) - plt.imshow(img2),plt.show() - -See the result below: - - .. image:: images/orb_kp.jpg - :alt: ORB Keypoints - :align: center - - -ORB feature matching, we will do in another chapter. - -Additional Resources -========================== - -#. Ethan Rublee, Vincent Rabaud, Kurt Konolige, Gary R. Bradski: ORB: An efficient alternative to SIFT or SURF. ICCV 2011: 2564-2571. - - -Exercises -============== diff --git a/doc/py_tutorials/py_feature2d/py_shi_tomasi/py_shi_tomasi.rst b/doc/py_tutorials/py_feature2d/py_shi_tomasi/py_shi_tomasi.rst deleted file mode 100644 index 566f555207..0000000000 --- a/doc/py_tutorials/py_feature2d/py_shi_tomasi/py_shi_tomasi.rst +++ /dev/null @@ -1,77 +0,0 @@ -.. _shi_tomasi: - -Shi-Tomasi Corner Detector & Good Features to Track -******************************************************* - -Goal -======= - -In this chapter, - - * We will learn about the another corner detector: Shi-Tomasi Corner Detector - * We will see the function: **cv2.goodFeaturesToTrack()** - -Theory -========= - -In last chapter, we saw Harris Corner Detector. Later in 1994, J. Shi and C. Tomasi made a small modification to it in their paper **Good Features to Track** which shows better results compared to Harris Corner Detector. The scoring function in Harris Corner Detector was given by: - -.. math:: - - R = \lambda_1 \lambda_2 - k(\lambda_1+\lambda_2)^2 - -Instead of this, Shi-Tomasi proposed: - -.. math:: - - R = min(\lambda_1, \lambda_2) - -If it is a greater than a threshold value, it is considered as a corner. If we plot it in :math:`\lambda_1 - \lambda_2` space as we did in Harris Corner Detector, we get an image as below: - - .. image:: images/shitomasi_space.png - :alt: Shi-Tomasi Corner Space - :align: center - -From the figure, you can see that only when :math:`\lambda_1` and :math:`\lambda_2` are above a minimum value, :math:`\lambda_{min}`, it is conidered as a corner(green region). - -Code -======= - -OpenCV has a function, **cv2.goodFeaturesToTrack()**. It finds N strongest corners in the image by Shi-Tomasi method (or Harris Corner Detection, if you specify it). As usual, image should be a grayscale image. Then you specify number of corners you want to find. Then you specify the quality level, which is a value between 0-1, which denotes the minimum quality of corner below which everyone is rejected. Then we provide the minimum euclidean distance between corners detected. - -With all these informations, the function finds corners in the image. All corners below quality level are rejected. Then it sorts the remaining corners based on quality in the descending order. Then function takes first strongest corner, throws away all the nearby corners in the range of minimum distance and returns N strongest corners. - -In below example, we will try to find 25 best corners: -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img = cv2.imread('simple.jpg') - gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - - corners = cv2.goodFeaturesToTrack(gray,25,0.01,10) - corners = np.int0(corners) - - for i in corners: - x,y = i.ravel() - cv2.circle(img,(x,y),3,255,-1) - - plt.imshow(img),plt.show() - -See the result below: - - .. image:: images/shitomasi_block1.jpg - :alt: Shi-Tomasi Corners - :align: center - - -This function is more appropriate for tracking. We will see that when its time comes. - -Additional Resources -====================== - - -Exercises -============ diff --git a/doc/py_tutorials/py_feature2d/py_sift_intro/py_sift_intro.rst b/doc/py_tutorials/py_feature2d/py_sift_intro/py_sift_intro.rst deleted file mode 100644 index 319c414e53..0000000000 --- a/doc/py_tutorials/py_feature2d/py_sift_intro/py_sift_intro.rst +++ /dev/null @@ -1,139 +0,0 @@ -.. _sift_intro: - - -Introduction to SIFT (Scale-Invariant Feature Transform) -************************************************************* - -Goal -====== - -In this chapter, - * We will learn about the concepts of SIFT algorithm - * We will learn to find SIFT Keypoints and Descriptors. - - -Theory -======== - -In last couple of chapters, we saw some corner detectors like Harris etc. They are rotation-invariant, which means, even if the image is rotated, we can find the same corners. It is obvious because corners remain corners in rotated image also. But what about scaling? A corner may not be a corner if the image is scaled. For example, check a simple image below. A corner in a small image within a small window is flat when it is zoomed in the same window. So Harris corner is not scale invariant. - - .. image:: images/sift_scale_invariant.jpg - :alt: Scale-Invariance - :align: center - -So, in 2004, **D.Lowe**, University of British Columbia, came up with a new algorithm, Scale Invariant Feature Transform (SIFT) in his paper, **Distinctive Image Features from Scale-Invariant Keypoints**, which extract keypoints and compute its descriptors. *(This paper is easy to understand and considered to be best material available on SIFT. So this explanation is just a short summary of this paper)*. - -There are mainly four steps involved in SIFT algorithm. We will see them one-by-one. - -1. Scale-space Extrema Detection --------------------------------------- - -From the image above, it is obvious that we can't use the same window to detect keypoints with different scale. It is OK with small corner. But to detect larger corners we need larger windows. For this, scale-space filtering is used. In it, Laplacian of Gaussian is found for the image with various :math:`\sigma` values. LoG acts as a blob detector which detects blobs in various sizes due to change in :math:`\sigma`. In short, :math:`\sigma` acts as a scaling parameter. For eg, in the above image, gaussian kernel with low :math:`\sigma` gives high value for small corner while guassian kernel with high :math:`\sigma` fits well for larger corner. So, we can find the local maxima across the scale and space which gives us a list of :math:`(x,y,\sigma)` values which means there is a potential keypoint at (x,y) at :math:`\sigma` scale. - -But this LoG is a little costly, so SIFT algorithm uses Difference of Gaussians which is an approximation of LoG. Difference of Gaussian is obtained as the difference of Gaussian blurring of an image with two different :math:`\sigma`, let it be :math:`\sigma` and :math:`k\sigma`. This process is done for different octaves of the image in Gaussian Pyramid. It is represented in below image: - - - .. image:: images/sift_dog.jpg - :alt: Difference of Gaussian - :align: center - -Once this DoG are found, images are searched for local extrema over scale and space. For eg, one pixel in an image is compared with its 8 neighbours as well as 9 pixels in next scale and 9 pixels in previous scales. If it is a local extrema, it is a potential keypoint. It basically means that keypoint is best represented in that scale. It is shown in below image: - - .. image:: images/sift_local_extrema.jpg - :alt: Difference of Gaussian - :align: center - -Regarding different parameters, the paper gives some empirical data which can be summarized as, number of octaves = 4, number of scale levels = 5, initial :math:`\sigma=1.6`, :math:`k=\sqrt{2}` etc as optimal values. - - -2. Keypoint Localization ------------------------------------- - -Once potential keypoints locations are found, they have to be refined to get more accurate results. They used Taylor series expansion of scale space to get more accurate location of extrema, and if the intensity at this extrema is less than a threshold value (0.03 as per the paper), it is rejected. This threshold is called **contrastThreshold** in OpenCV - -DoG has higher response for edges, so edges also need to be removed. For this, a concept similar to Harris corner detector is used. They used a 2x2 Hessian matrix (H) to compute the pricipal curvature. We know from Harris corner detector that for edges, one eigen value is larger than the other. So here they used a simple function, - -.. math: - - \frac{Tr(H)^2}{Det(H)} < \frac{(r+1)^2}{r} \; \text{where} \; r = \frac{\lambda_1}{\lambda_2}; \; \lambda_1 > \lambda_2 - -If this ratio is greater than a threshold, called **edgeThreshold** in OpenCV, that keypoint is discarded. It is given as 10 in paper. - -So it eliminates any low-contrast keypoints and edge keypoints and what remains is strong interest points. - -3. Orientation Assignment ------------------------------------ - -Now an orientation is assigned to each keypoint to achieve invariance to image rotation. A neigbourhood is taken around the keypoint location depending on the scale, and the gradient magnitude and direction is calculated in that region. An orientation histogram with 36 bins covering 360 degrees is created. (It is weighted by gradient magnitude and gaussian-weighted circular window with :math:`\sigma` equal to 1.5 times the scale of keypoint. The highest peak in the histogram is taken and any peak above 80% of it is also considered to calculate the orientation. It creates keypoints with same location and scale, but different directions. It contribute to stability of matching. - - -4. Keypoint Descriptor ------------------------------------------ - -Now keypoint descriptor is created. A 16x16 neighbourhood around the keypoint is taken. It is devided into 16 sub-blocks of 4x4 size. For each sub-block, 8 bin orientation histogram is created. So a total of 128 bin values are available. It is represented as a vector to form keypoint descriptor. In addition to this, several measures are taken to achieve robustness against illumination changes, rotation etc. - -5. Keypoint Matching ----------------------------------------- - -Keypoints between two images are matched by identifying their nearest neighbours. But in some cases, the second closest-match may be very near to the first. It may happen due to noise or some other reasons. In that case, ratio of closest-distance to second-closest distance is taken. If it is greater than 0.8, they are rejected. It eliminaters around 90% of false matches while discards only 5% correct matches, as per the paper. - -So this is a summary of SIFT algorithm. For more details and understanding, reading the original paper is highly recommended. Remember one thing, this algorithm is patented. So this algorithm is included in Non-free module in OpenCV. - - -SIFT in OpenCV -================= - -So now let's see SIFT functionalities available in OpenCV. Let's start with keypoint detection and draw them. First we have to construct a SIFT object. We can pass different parameters to it which are optional and they are well explained in docs. -:: - - import cv2 - import numpy as np - - img = cv2.imread('home.jpg') - gray= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - - sift = cv2.SIFT() - kp = sift.detect(gray,None) - - img=cv2.drawKeypoints(gray,kp) - - cv2.imwrite('sift_keypoints.jpg',img) - -**sift.detect()** function finds the keypoint in the images. You can pass a mask if you want to search only a part of image. Each keypoint is a special structure which has many attributes like its (x,y) coordinates, size of the meaningful neighbourhood, angle which specifies its orientation, response that specifies strength of keypoints etc. - -OpenCV also provides **cv2.drawKeyPoints()** function which draws the small circles on the locations of keypoints. If you pass a flag, **cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS** to it, it will draw a circle with size of keypoint and it will even show its orientation. See below example. -:: - - img=cv2.drawKeypoints(gray,kp,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) - cv2.imwrite('sift_keypoints.jpg',img) - -See the two results below: - - .. image:: images/sift_keypoints.jpg - :alt: SIFT Keypoints - :align: center - -Now to calculate the descriptor, OpenCV provides two methods. - -1. Since you already found keypoints, you can call **sift.compute()** which computes the descriptors from the keypoints we have found. Eg: ``kp,des = sift.compute(gray,kp)`` - -2. If you didn't find keypoints, directly find keypoints and descriptors in a single step with the function, **sift.detectAndCompute()**. - -We will see the second method: -:: - - sift = cv2.SIFT() - kp, des = sift.detectAndCompute(gray,None) - -Here kp will be a list of keypoints and des is a numpy array of shape :math:`Number\_of\_Keypoints \times 128`. - -So we got keypoints, descriptors etc. Now we want to see how to match keypoints in different images. That we will learn in coming chapters. - - -Additional Resources -===================== - - - -Exercises -============= diff --git a/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.rst b/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.rst deleted file mode 100644 index 1b8f50d84f..0000000000 --- a/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.rst +++ /dev/null @@ -1,145 +0,0 @@ -.. _SURF: - - -Introduction to SURF (Speeded-Up Robust Features) -***************************************************** - -Goal -====== - -In this chapter, - * We will see the basics of SURF - * We will see SURF functionalities in OpenCV - - -Theory -========== - -In last chapter, we saw SIFT for keypoint detection and description. But it was comparatively slow and people needed more speeded-up version. In 2006, three people, Bay, H., Tuytelaars, T. and Van Gool, L, published another paper, "SURF: Speeded Up Robust Features" which introduced a new algorithm called SURF. As name suggests, it is a speeded-up version of SIFT. - -In SIFT, Lowe approximated Laplacian of Gaussian with Difference of Gaussian for finding scale-space. SURF goes a little further and approximates LoG with Box Filter. Below image shows a demonstration of such an approximation. One big advantage of this approximation is that, convolution with box filter can be easily calculated with the help of integral images. And it can be done in parallel for different scales. Also the SURF rely on determinant of Hessian matrix for both scale and location. - - .. image:: images/surf_boxfilter.jpg - :alt: Box Filter approximation of Laplacian - :align: center - - -For orientation assignment, SURF uses wavelet responses in horizontal and vertical direction for a neighbourhood of size 6s. Adequate guassian weights are also applied to it. Then they are plotted in a space as given in below image. The dominant orientation is estimated by calculating the sum of all responses within a sliding orientation window of angle 60 degrees. Interesting thing is that, wavelet response can be found out using integral images very easily at any scale. For many applications, rotation invariance is not required, so no need of finding this orientation, which speeds up the process. SURF provides such a functionality called Upright-SURF or U-SURF. It improves speed and is robust upto :math:`\pm 15^{\circ}`. OpenCV supports both, depending upon the flag, **upright**. If it is 0, orientation is calculated. If it is 1, orientation is not calculated and it is more faster. - - .. image:: images/surf_orientation.jpg - :alt: Orientation Assignment in SURF - :align: center - -For feature description, SURF uses Wavelet responses in horizontal and vertical direction (again, use of integral images makes things easier). A neighbourhood of size 20sX20s is taken around the keypoint where s is the size. It is divided into 4x4 subregions. For each subregion, horizontal and vertical wavelet responses are taken and a vector is formed like this, :math:`v=( \sum{d_x}, \sum{d_y}, \sum{|d_x|}, \sum{|d_y|})`. This when represented as a vector gives SURF feature descriptor with total 64 dimensions. Lower the dimension, higher the speed of computation and matching, but provide better distinctiveness of features. - -For more distinctiveness, SURF feature descriptor has an extended 128 dimension version. The sums of :math:`d_x` and :math:`|d_x|` are computed separately for :math:`d_y < 0` and :math:`d_y \geq 0`. Similarly, the sums of :math:`d_y` and :math:`|d_y|` are split -up according to the sign of :math:`d_x` , thereby doubling the number of features. It doesn't add much computation complexity. OpenCV supports both by setting the value of flag **extended** with 0 and 1 for 64-dim and 128-dim respectively (default is 128-dim) - -Another important improvement is the use of sign of Laplacian (trace of Hessian Matrix) for underlying interest point. It adds no computation cost since it is already computed during detection. The sign of the Laplacian distinguishes bright blobs on dark backgrounds from the reverse situation. In the matching stage, we only compare features if they have the same type of contrast (as shown in image below). This minimal information allows for faster matching, without reducing the descriptor's performance. - - .. image:: images/surf_matching.jpg - :alt: Fast Indexing for Matching - :align: center - -In short, SURF adds a lot of features to improve the speed in every step. Analysis shows it is 3 times faster than SIFT while performance is comparable to SIFT. SURF is good at handling images with blurring and rotation, but not good at handling viewpoint change and illumination change. - - -SURF in OpenCV -==================== - -OpenCV provides SURF functionalities just like SIFT. You initiate a SURF object with some optional conditions like 64/128-dim descriptors, Upright/Normal SURF etc. All the details are well explained in docs. Then as we did in SIFT, we can use SURF.detect(), SURF.compute() etc for finding keypoints and descriptors. - -First we will see a simple demo on how to find SURF keypoints and descriptors and draw it. All examples are shown in Python terminal since it is just same as SIFT only. -:: - - >>> img = cv2.imread('fly.png',0) - - # Create SURF object. You can specify params here or later. - # Here I set Hessian Threshold to 400 - >>> surf = cv2.SURF(400) - - # Find keypoints and descriptors directly - >>> kp, des = surf.detectAndCompute(img,None) - - >>> len(kp) - 699 - - -1199 keypoints is too much to show in a picture. We reduce it to some 50 to draw it on an image. While matching, we may need all those features, but not now. So we increase the Hessian Threshold. -:: - - # Check present Hessian threshold - >>> print surf.hessianThreshold - 400.0 - - # We set it to some 50000. Remember, it is just for representing in picture. - # In actual cases, it is better to have a value 300-500 - >>> surf.hessianThreshold = 50000 - - # Again compute keypoints and check its number. - >>> kp, des = surf.detectAndCompute(img,None) - - >>> print len(kp) - 47 - -It is less than 50. Let's draw it on the image. -:: - - >>> img2 = cv2.drawKeypoints(img,kp,None,(255,0,0),4) - - >>> plt.imshow(img2),plt.show() - -See the result below. You can see that SURF is more like a blob detector. It detects the white blobs on wings of butterfly. You can test it with other images. - - .. image:: images/surf_kp1.jpg - :alt: SURF Keypoints with Orientation - :align: center - -Now I want to apply U-SURF, so that it won't find the orientation. -:: - - # Check upright flag, if it False, set it to True - >>> print surf.upright - False - - >>> surf.upright = True - - # Recompute the feature points and draw it - >>> kp = surf.detect(img,None) - >>> img2 = cv2.drawKeypoints(img,kp,None,(255,0,0),4) - - >>> plt.imshow(img2),plt.show() - -See the results below. All the orientations are shown in same direction. It is more faster than previous. If you are working on cases where orientation is not a problem (like panorama stitching) etc, this is better. - - .. image:: images/surf_kp2.jpg - :alt: Upright-SURF - :align: center - -Finally we check the descriptor size and change it to 128 if it is only 64-dim. -:: - - # Find size of descriptor - >>> print surf.descriptorSize() - 64 - - # That means flag, "extended" is False. - >>> surf.extended - False - - # So we make it to True to get 128-dim descriptors. - >>> surf.extended = True - >>> kp, des = surf.detectAndCompute(img,None) - >>> print surf.descriptorSize() - 128 - >>> print des.shape - (47, 128) - -Remaining part is matching which we will do in another chapter. - -Additional Resources -======================= - - -Exercises -============== diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/py_table_of_contents_feature2d.markdown b/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d.markdown similarity index 100% rename from doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/py_table_of_contents_feature2d.markdown rename to doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d.markdown diff --git a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/py_table_of_contents_feature2d.rst b/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/py_table_of_contents_feature2d.rst deleted file mode 100644 index 0e20445a1b..0000000000 --- a/doc/py_tutorials/py_feature2d/py_table_of_contents_feature2d/py_table_of_contents_feature2d.rst +++ /dev/null @@ -1,170 +0,0 @@ -.. _PY_Table-Of-Content-Feature2D: - -Feature Detection and Description ------------------------------------------- - -* :ref:`Features_Meaning` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |f2d_1| What are the main features in an image? How can finding those features be useful to us? - - =========== ====================================================== - - .. |f2d_1| image:: images/features_icon.jpg - :height: 90pt - :width: 90pt - - -* :ref:`Harris_Corners` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |f2d_2| Okay, Corners are good features? But how do we find them? - - =========== ====================================================== - - .. |f2d_2| image:: images/harris_icon.jpg - :height: 90pt - :width: 90pt - - -* :ref:`shi_tomasi` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |f2d_3| We will look into Shi-Tomasi corner detection - - =========== ====================================================== - - .. |f2d_3| image:: images/shi_icon.jpg - :height: 90pt - :width: 90pt - - -* :ref:`sift_intro` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |f2d_4| Harris corner detector is not good enough when scale of image changes. Lowe developed a breakthrough method to find scale-invariant features and it is called SIFT - - =========== ====================================================== - - .. |f2d_4| image:: images/sift_icon.jpg - :height: 90pt - :width: 90pt - - -* :ref:`SURF` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |f2d_5| SIFT is really good, but not fast enough, so people came up with a speeded-up version called SURF. - - =========== ====================================================== - - .. |f2d_5| image:: images/surf_icon.jpg - :height: 90pt - :width: 90pt - - -* :ref:`FAST` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |f2d_06| All the above feature detection methods are good in some way. But they are not fast enough to work in real-time applications like SLAM. There comes the FAST algorithm, which is really "FAST". - - =========== ====================================================== - - .. |f2d_06| image:: images/fast_icon.jpg - :height: 90pt - :width: 90pt - - -* :ref:`BRIEF` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |f2d_07| SIFT uses a feature descriptor with 128 floating point numbers. Consider thousands of such features. It takes lots of memory and more time for matching. We can compress it to make it faster. But still we have to calculate it first. There comes BRIEF which gives the shortcut to find binary descriptors with less memory, faster matching, still higher recognition rate. - - =========== ====================================================== - - .. |f2d_07| image:: images/brief.jpg - :height: 90pt - :width: 90pt - - -* :ref:`ORB` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |f2d_08| SIFT and SURF are good in what they do, but what if you have to pay a few dollars every year to use them in your applications? Yeah, they are patented!!! To solve that problem, OpenCV devs came up with a new "FREE" alternative to SIFT & SURF, and that is ORB. - =========== ====================================================== - - .. |f2d_08| image:: images/orb.jpg - :height: 90pt - :width: 90pt - - -* :ref:`Matcher` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |f2d_09| We know a great deal about feature detectors and descriptors. It is time to learn how to match different descriptors. OpenCV provides two techniques, Brute-Force matcher and FLANN based matcher. - =========== ====================================================== - - .. |f2d_09| image:: images/matching.jpg - :height: 90pt - :width: 90pt - - -* :ref:`PY_feature_homography` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |f2d_10| Now we know about feature matching. Let's mix it up with `calib3d` module to find objects in a complex image. - =========== ====================================================== - - .. |f2d_10| image:: images/homography_icon.jpg - :height: 90pt - :width: 90pt - - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_features_meaning/py_features_meaning - ../py_features_harris/py_features_harris - ../py_shi_tomasi/py_shi_tomasi - ../py_sift_intro/py_sift_intro - ../py_surf_intro/py_surf_intro - ../py_fast/py_fast - ../py_brief/py_brief - ../py_orb/py_orb - ../py_matcher/py_matcher - ../py_feature_homography/py_feature_homography diff --git a/doc/py_tutorials/py_gui/py_table_of_contents_gui/images/drawing.jpg b/doc/py_tutorials/py_gui/images/drawing.jpg similarity index 100% rename from doc/py_tutorials/py_gui/py_table_of_contents_gui/images/drawing.jpg rename to doc/py_tutorials/py_gui/images/drawing.jpg diff --git a/doc/py_tutorials/py_gui/py_table_of_contents_gui/images/image_display.jpg b/doc/py_tutorials/py_gui/images/image_display.jpg similarity index 100% rename from doc/py_tutorials/py_gui/py_table_of_contents_gui/images/image_display.jpg rename to doc/py_tutorials/py_gui/images/image_display.jpg diff --git a/doc/py_tutorials/py_gui/py_table_of_contents_gui/images/mouse_drawing.jpg b/doc/py_tutorials/py_gui/images/mouse_drawing.jpg similarity index 100% rename from doc/py_tutorials/py_gui/py_table_of_contents_gui/images/mouse_drawing.jpg rename to doc/py_tutorials/py_gui/images/mouse_drawing.jpg diff --git a/doc/py_tutorials/py_gui/py_table_of_contents_gui/images/trackbar.jpg b/doc/py_tutorials/py_gui/images/trackbar.jpg similarity index 100% rename from doc/py_tutorials/py_gui/py_table_of_contents_gui/images/trackbar.jpg rename to doc/py_tutorials/py_gui/images/trackbar.jpg diff --git a/doc/py_tutorials/py_gui/py_table_of_contents_gui/images/video_display.jpg b/doc/py_tutorials/py_gui/images/video_display.jpg similarity index 100% rename from doc/py_tutorials/py_gui/py_table_of_contents_gui/images/video_display.jpg rename to doc/py_tutorials/py_gui/images/video_display.jpg diff --git a/doc/py_tutorials/py_gui/py_drawing_functions/py_drawing_functions.rst b/doc/py_tutorials/py_gui/py_drawing_functions/py_drawing_functions.rst deleted file mode 100644 index 97d750c642..0000000000 --- a/doc/py_tutorials/py_gui/py_drawing_functions/py_drawing_functions.rst +++ /dev/null @@ -1,106 +0,0 @@ -.. _Drawing_Functions: - -Drawing Functions in OpenCV -****************************** - -Goal -===== - -.. container:: enumeratevisibleitemswithsquare - - * Learn to draw different geometric shapes with OpenCV - * You will learn these functions : **cv2.line()**, **cv2.circle()** , **cv2.rectangle()**, **cv2.ellipse()**, **cv2.putText()** etc. - -Code -===== - -In all the above functions, you will see some common arguments as given below: - - * img : The image where you want to draw the shapes - * color : Color of the shape. for BGR, pass it as a tuple, eg: ``(255,0,0)`` for blue. For grayscale, just pass the scalar value. - * thickness : Thickness of the line or circle etc. If **-1** is passed for closed figures like circles, it will fill the shape. *default thickness = 1* - * lineType : Type of line, whether 8-connected, anti-aliased line etc. *By default, it is 8-connected.* ``cv2.LINE_AA`` gives anti-aliased line which looks great for curves. - -Drawing Line -------------- -To draw a line, you need to pass starting and ending coordinates of line. We will create a black image and draw a blue line on it from top-left to bottom-right corners. -:: - - import numpy as np - import cv2 - - # Create a black image - img = np.zeros((512,512,3), np.uint8) - - # Draw a diagonal blue line with thickness of 5 px - cv2.line(img,(0,0),(511,511),(255,0,0),5) - -Drawing Rectangle -------------------- -To draw a rectangle, you need top-left corner and bottom-right corner of rectangle. This time we will draw a green rectangle at the top-right corner of image. -:: - - cv2.rectangle(img,(384,0),(510,128),(0,255,0),3) - -Drawing Circle ----------------- -To draw a circle, you need its center coordinates and radius. We will draw a circle inside the rectangle drawn above. -:: - - cv2.circle(img,(447,63), 63, (0,0,255), -1) - -Drawing Ellipse --------------------- - -To draw the ellipse, we need to pass several arguments. One argument is the center location (x,y). Next argument is axes lengths (major axis length, minor axis length). ``angle`` is the angle of rotation of ellipse in anti-clockwise direction. ``startAngle`` and ``endAngle`` denotes the starting and ending of ellipse arc measured in clockwise direction from major axis. i.e. giving values 0 and 360 gives the full ellipse. For more details, check the documentation of **cv2.ellipse()**. Below example draws a half ellipse at the center of the image. -:: - - cv2.ellipse(img,(256,256),(100,50),0,0,180,255,-1) - - -Drawing Polygon ------------------- -To draw a polygon, first you need coordinates of vertices. Make those points into an array of shape ``ROWSx1x2`` where ROWS are number of vertices and it should be of type ``int32``. Here we draw a small polygon of with four vertices in yellow color. -:: - - pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32) - pts = pts.reshape((-1,1,2)) - cv2.polylines(img,[pts],True,(0,255,255)) - -.. Note:: If third argument is ``False``, you will get a polylines joining all the points, not a closed shape. - -.. Note:: ``cv2.polylines()`` can be used to draw multiple lines. Just create a list of all the lines you want to draw and pass it to the function. All lines will be drawn individually. It is a much better and faster way to draw a group of lines than calling ``cv2.line()`` for each line. - -Adding Text to Images: ------------------------- -To put texts in images, you need specify following things. - * Text data that you want to write - * Position coordinates of where you want put it (i.e. bottom-left corner where data starts). - * Font type (Check **cv2.putText()** docs for supported fonts) - * Font Scale (specifies the size of font) - * regular things like color, thickness, lineType etc. For better look, ``lineType = cv2.LINE_AA`` is recommended. - -We will write **OpenCV** on our image in white color. -:: - - font = cv2.FONT_HERSHEY_SIMPLEX - cv2.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv2.LINE_AA) - -Result ----------- -So it is time to see the final result of our drawing. As you studied in previous articles, display the image to see it. - - .. image:: images/drawing_result.jpg - :alt: Drawing Functions in OpenCV - :align: center - - -Additional Resources -======================== - -1. The angles used in ellipse function is not our circular angles. For more details, visit `this discussion `_. - - -Exercises -============== -#. Try to create the logo of OpenCV using drawing functions available in OpenCV. diff --git a/doc/py_tutorials/py_gui/py_image_display/py_image_display.rst b/doc/py_tutorials/py_gui/py_image_display/py_image_display.rst deleted file mode 100644 index a05db370c1..0000000000 --- a/doc/py_tutorials/py_gui/py_image_display/py_image_display.rst +++ /dev/null @@ -1,141 +0,0 @@ -.. _PY_Display_Image: - -Getting Started with Images -***************************** - -Goals -====== - -.. container:: enumeratevisibleitemswithsquare - - * Here, you will learn how to read an image, how to display it and how to save it back - * You will learn these functions : **cv2.imread()**, **cv2.imshow()** , **cv2.imwrite()** - * Optionally, you will learn how to display images with Matplotlib - -Using OpenCV -============= - -Read an image --------------- - -Use the function **cv2.imread()** to read an image. The image should be in the working directory or a full path of image should be given. - -Second argument is a flag which specifies the way image should be read. - -* cv2.IMREAD_COLOR : Loads a color image. Any transparency of image will be neglected. It is the default flag. -* cv2.IMREAD_GRAYSCALE : Loads image in grayscale mode -* cv2.IMREAD_UNCHANGED : Loads image as such including alpha channel - -.. note:: Instead of these three flags, you can simply pass integers 1, 0 or -1 respectively. - -See the code below: -:: - - import numpy as np - import cv2 - - # Load an color image in grayscale - img = cv2.imread('messi5.jpg',0) - -.. warning:: Even if the image path is wrong, it won't throw any error, but ``print img`` will give you ``None`` - -Display an image ------------------ - -Use the function **cv2.imshow()** to display an image in a window. The window automatically fits to the image size. - -First argument is a window name which is a string. second argument is our image. You can create as many windows as you wish, but with different window names. -:: - - cv2.imshow('image',img) - cv2.waitKey(0) - cv2.destroyAllWindows() - -A screenshot of the window will look like this (in Fedora-Gnome machine): - - .. image:: images/opencv_screenshot.jpg - :alt: Screenshot of Image Window in OpenCV - :align: center - -**cv2.waitKey()** is a keyboard binding function. Its argument is the time in milliseconds. The function waits for specified milliseconds for any keyboard event. If you press any key in that time, the program continues. If **0** is passed, it waits indefinitely for a key stroke. It can also be set to detect specific key strokes like, if key `a` is pressed etc which we will discuss below. - -.. note:: Besides binding keyboard events this function also processes many other GUI events, so you MUST use it to actually display the image. - -**cv2.destroyAllWindows()** simply destroys all the windows we created. If you want to destroy any specific window, use the function **cv2.destroyWindow()** where you pass the exact window name as the argument. - -.. note:: There is a special case where you can already create a window and load image to it later. In that case, you can specify whether window is resizable or not. It is done with the function **cv2.namedWindow()**. By default, the flag is ``cv2.WINDOW_AUTOSIZE``. But if you specify flag to be ``cv2.WINDOW_NORMAL``, you can resize window. It will be helpful when image is too large in dimension and adding track bar to windows. - -See the code below: -:: - - cv2.namedWindow('image', cv2.WINDOW_NORMAL) - cv2.imshow('image',img) - cv2.waitKey(0) - cv2.destroyAllWindows() - -Write an image ---------------- - -Use the function **cv2.imwrite()** to save an image. - -First argument is the file name, second argument is the image you want to save. -:: - - cv2.imwrite('messigray.png',img) - -This will save the image in PNG format in the working directory. - -Sum it up ---------------- - -Below program loads an image in grayscale, displays it, save the image if you press 's' and exit, or simply exit without saving if you press `ESC` key. -:: - - import numpy as np - import cv2 - - img = cv2.imread('messi5.jpg',0) - cv2.imshow('image',img) - k = cv2.waitKey(0) - if k == 27: # wait for ESC key to exit - cv2.destroyAllWindows() - elif k == ord('s'): # wait for 's' key to save and exit - cv2.imwrite('messigray.png',img) - cv2.destroyAllWindows() - -.. warning:: If you are using a 64-bit machine, you will have to modify ``k = cv2.waitKey(0)`` line as follows : ``k = cv2.waitKey(0) & 0xFF`` - -Using Matplotlib -================= - -Matplotlib is a plotting library for Python which gives you wide variety of plotting methods. You will see them in coming articles. Here, you will learn how to display image with Matplotlib. You can zoom images, save it etc using Matplotlib. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img = cv2.imread('messi5.jpg',0) - plt.imshow(img, cmap = 'gray', interpolation = 'bicubic') - plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis - plt.show() - -A screen-shot of the window will look like this : - - .. image:: images/matplotlib_screenshot.jpg - :alt: Screenshot of Image Window in Matplotlib - :align: center - -.. seealso:: Plenty of plotting options are available in Matplotlib. Please refer to Matplotlib docs for more details. Some, we will see on the way. - -.. warning:: Color image loaded by OpenCV is in BGR mode. But Matplotlib displays in RGB mode. So color images will not be displayed correctly in Matplotlib if image is read with OpenCV. Please see the exercises for more details. - -Additional Resources -====================== - -#. `Matplotlib Plotting Styles and Features `_ - -Exercises -========== - -#. There is some problem when you try to load color image in OpenCV and display it in Matplotlib. Read `this discussion `_ and understand it. diff --git a/doc/py_tutorials/py_gui/py_mouse_handling/py_mouse_handling.rst b/doc/py_tutorials/py_gui/py_mouse_handling/py_mouse_handling.rst deleted file mode 100644 index 4162411899..0000000000 --- a/doc/py_tutorials/py_gui/py_mouse_handling/py_mouse_handling.rst +++ /dev/null @@ -1,108 +0,0 @@ -.. _Mouse_Handling: - -Mouse as a Paint-Brush -*********************** - -Goal -====== - -.. container:: enumeratevisibleitemswithsquare - - * Learn to handle mouse events in OpenCV - * You will learn these functions : **cv2.setMouseCallback()** - -Simple Demo -============= - -Here, we create a simple application which draws a circle on an image wherever we double-click on it. - -First we create a mouse callback function which is executed when a mouse event take place. Mouse event can be anything related to mouse like left-button down, left-button up, left-button double-click etc. It gives us the coordinates (x,y) for every mouse event. With this event and location, we can do whatever we like. To list all available events available, run the following code in Python terminal: -:: - - >>> import cv2 - >>> events = [i for i in dir(cv2) if 'EVENT' in i] - >>> print events - -Creating mouse callback function has a specific format which is same everywhere. It differs only in what the function does. So our mouse callback function does one thing, it draws a circle where we double-click. So see the code below. Code is self-explanatory from comments : -:: - - import cv2 - import numpy as np - - # mouse callback function - def draw_circle(event,x,y,flags,param): - if event == cv2.EVENT_LBUTTONDBLCLK: - cv2.circle(img,(x,y),100,(255,0,0),-1) - - # Create a black image, a window and bind the function to window - img = np.zeros((512,512,3), np.uint8) - cv2.namedWindow('image') - cv2.setMouseCallback('image',draw_circle) - - while(1): - cv2.imshow('image',img) - if cv2.waitKey(20) & 0xFF == 27: - break - cv2.destroyAllWindows() - -More Advanced Demo -=================== - -Now we go for a much better application. In this, we draw either rectangles or circles (depending on the mode we select) by dragging the mouse like we do in Paint application. So our mouse callback function has two parts, one to draw rectangle and other to draw the circles. This specific example will be really helpful in creating and understanding some interactive applications like object tracking, image segmentation etc. -:: - - import cv2 - import numpy as np - - drawing = False # true if mouse is pressed - mode = True # if True, draw rectangle. Press 'm' to toggle to curve - ix,iy = -1,-1 - - # mouse callback function - def draw_circle(event,x,y,flags,param): - global ix,iy,drawing,mode - - if event == cv2.EVENT_LBUTTONDOWN: - drawing = True - ix,iy = x,y - - elif event == cv2.EVENT_MOUSEMOVE: - if drawing == True: - if mode == True: - cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1) - else: - cv2.circle(img,(x,y),5,(0,0,255),-1) - - elif event == cv2.EVENT_LBUTTONUP: - drawing = False - if mode == True: - cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1) - else: - cv2.circle(img,(x,y),5,(0,0,255),-1) - -Next we have to bind this mouse callback function to OpenCV window. In the main loop, we should set a keyboard binding for key 'm' to toggle between rectangle and circle. -:: - - img = np.zeros((512,512,3), np.uint8) - cv2.namedWindow('image') - cv2.setMouseCallback('image',draw_circle) - - while(1): - cv2.imshow('image',img) - k = cv2.waitKey(1) & 0xFF - if k == ord('m'): - mode = not mode - elif k == 27: - break - - cv2.destroyAllWindows() - - -Additional Resources -======================== - - -Exercises -========== - -#. In our last example, we drew filled rectangle. You modify the code to draw an unfilled rectangle. diff --git a/doc/py_tutorials/py_gui/py_table_of_contents_gui/py_table_of_contents_gui.markdown b/doc/py_tutorials/py_gui/py_table_of_contents_gui.markdown similarity index 100% rename from doc/py_tutorials/py_gui/py_table_of_contents_gui/py_table_of_contents_gui.markdown rename to doc/py_tutorials/py_gui/py_table_of_contents_gui.markdown diff --git a/doc/py_tutorials/py_gui/py_table_of_contents_gui/py_table_of_contents_gui.rst b/doc/py_tutorials/py_gui/py_table_of_contents_gui/py_table_of_contents_gui.rst deleted file mode 100644 index b709abf794..0000000000 --- a/doc/py_tutorials/py_gui/py_table_of_contents_gui/py_table_of_contents_gui.rst +++ /dev/null @@ -1,89 +0,0 @@ -.. _PY_Table-Of-Content-Gui: - -Gui Features in OpenCV ------------------------------------------------------------ - - -* :ref:`PY_Display_Image` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |gui_1| Learn to load an image, display it and save it back - - =========== ====================================================== - - .. |gui_1| image:: images/image_display.jpg - :height: 90pt - :width: 90pt - -* :ref:`Display_Video` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |gui_2| Learn to play videos, capture videos from Camera and write it as a video - - =========== ====================================================== - - .. |gui_2| image:: images/video_display.jpg - :height: 90pt - :width: 90pt - -* :ref:`Drawing_Functions` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |gui_5| Learn to draw lines, rectangles, ellipses, circles etc with OpenCV - - =========== ====================================================== - - .. |gui_5| image:: images/drawing.jpg - :height: 90pt - :width: 90pt - -* :ref:`Mouse_Handling` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |gui_3| Draw stuffs with your mouse - - =========== ====================================================== - - .. |gui_3| image:: images/mouse_drawing.jpg - :height: 90pt - :width: 90pt - -* :ref:`Trackbar` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |gui_4| Create trackbar to control certain parameters - - =========== ====================================================== - - .. |gui_4| image:: images/trackbar.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_image_display/py_image_display - ../py_video_display/py_video_display - ../py_drawing_functions/py_drawing_functions - ../py_mouse_handling/py_mouse_handling - ../py_trackbar/py_trackbar diff --git a/doc/py_tutorials/py_gui/py_trackbar/py_trackbar.rst b/doc/py_tutorials/py_gui/py_trackbar/py_trackbar.rst deleted file mode 100644 index 1db29851a6..0000000000 --- a/doc/py_tutorials/py_gui/py_trackbar/py_trackbar.rst +++ /dev/null @@ -1,71 +0,0 @@ -.. _Trackbar: - -Trackbar as the Color Palette -******************************** - -Goal -===== - -.. container:: enumeratevisibleitemswithsquare - - * Learn to bind trackbar to OpenCV windows - * You will learn these functions : **cv2.getTrackbarPos()**, **cv2.createTrackbar()** etc. - -Code Demo -========== - -Here we will create a simple application which shows the color you specify. You have a window which shows the color and three trackbars to specify each of B,G,R colors. You slide the trackbar and correspondingly window color changes. By default, initial color will be set to Black. - -For cv2.getTrackbarPos() function, first argument is the trackbar name, second one is the window name to which it is attached, third argument is the default value, fourth one is the maximum value and fifth one is the callback function which is executed everytime trackbar value changes. The callback function always has a default argument which is the trackbar position. In our case, function does nothing, so we simply pass. - -Another important application of trackbar is to use it as a button or switch. OpenCV, by default, doesn't have button functionality. So you can use trackbar to get such functionality. In our application, we have created one switch in which application works only if switch is ON, otherwise screen is always black. -:: - - import cv2 - import numpy as np - - def nothing(x): - pass - - # Create a black image, a window - img = np.zeros((300,512,3), np.uint8) - cv2.namedWindow('image') - - # create trackbars for color change - cv2.createTrackbar('R','image',0,255,nothing) - cv2.createTrackbar('G','image',0,255,nothing) - cv2.createTrackbar('B','image',0,255,nothing) - - # create switch for ON/OFF functionality - switch = '0 : OFF \n1 : ON' - cv2.createTrackbar(switch, 'image',0,1,nothing) - - while(1): - cv2.imshow('image',img) - k = cv2.waitKey(1) & 0xFF - if k == 27: - break - - # get current positions of four trackbars - r = cv2.getTrackbarPos('R','image') - g = cv2.getTrackbarPos('G','image') - b = cv2.getTrackbarPos('B','image') - s = cv2.getTrackbarPos(switch,'image') - - if s == 0: - img[:] = 0 - else: - img[:] = [b,g,r] - - cv2.destroyAllWindows() - -The screenshot of the application looks like below : - - .. image:: images/trackbar_screenshot.jpg - :alt: Screenshot of Image with Trackbars - :align: center - -Exercises -=========== - -#. Create a Paint application with adjustable colors and brush radius using trackbars. For drawing, refer previous tutorial on mouse handling. diff --git a/doc/py_tutorials/py_gui/py_video_display/py_video_display.rst b/doc/py_tutorials/py_gui/py_video_display/py_video_display.rst deleted file mode 100644 index 5bdf4fcb87..0000000000 --- a/doc/py_tutorials/py_gui/py_video_display/py_video_display.rst +++ /dev/null @@ -1,132 +0,0 @@ -.. _Display_Video: - -Getting Started with Videos -***************************** - -Goal -===== - -.. container:: enumeratevisibleitemswithsquare - - * Learn to read video, display video and save video. - * Learn to capture from Camera and display it. - * You will learn these functions : **cv2.VideoCapture()**, **cv2.VideoWriter()** - - -Capture Video from Camera -=========================== - -Often, we have to capture live stream with camera. OpenCV provides a very simple interface to this. Let's capture a video from the camera (I am using the in-built webcam of my laptop), convert it into grayscale video and display it. Just a simple task to get started. - -To capture a video, you need to create a **VideoCapture** object. Its argument can be either the device index or the name of a video file. Device index is just the number to specify which camera. Normally one camera will be connected (as in my case). So I simply pass 0 (or -1). You can select the second camera by passing 1 and so on. After that, you can capture frame-by-frame. But at the end, don't forget to release the capture. -:: - - import numpy as np - import cv2 - - cap = cv2.VideoCapture(0) - - while(True): - # Capture frame-by-frame - ret, frame = cap.read() - - # Our operations on the frame come here - gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) - - # Display the resulting frame - cv2.imshow('frame',gray) - if cv2.waitKey(1) & 0xFF == ord('q'): - break - - # When everything done, release the capture - cap.release() - cv2.destroyAllWindows() - -``cap.read()`` returns a bool (True/False). If frame is read correctly, it will be True. So you can check end of the video by checking this return value. - -Sometimes, ``cap`` may not have initialized the capture. In that case, this code shows error. You can check whether it is initialized or not by the method **cap.isOpened()**. If it is True, OK. Otherwise open it using **cap.open()**. - -You can also access some of the features of this video using **cap.get(propId)** method where propId is a number from 0 to 18. Each number denotes a property of the video (if it is applicable to that video) and full details can be seen here: `Property Identifier `_. Some of these values can be modified using **cap.set(propId, value)**. Value is the new value you want. - -For example, I can check the frame width and height by ``cap.get(3)`` and ``cap.get(4)``. It gives me 640x480 by default. But I want to modify it to 320x240. Just use ``ret = cap.set(3,320)`` and ``ret = cap.set(4,240)``. - -.. Note:: If you are getting error, make sure camera is working fine using any other camera application (like Cheese in Linux). - -Playing Video from file -======================== - -It is same as capturing from Camera, just change camera index with video file name. Also while displaying the frame, use appropriate time for ``cv2.waitKey()``. If it is too less, video will be very fast and if it is too high, video will be slow (Well, that is how you can display videos in slow motion). 25 milliseconds will be OK in normal cases. -:: - - import numpy as np - import cv2 - - cap = cv2.VideoCapture('vtest.avi') - - while(cap.isOpened()): - ret, frame = cap.read() - - gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) - - cv2.imshow('frame',gray) - if cv2.waitKey(1) & 0xFF == ord('q'): - break - - cap.release() - cv2.destroyAllWindows() - -.. Note:: Make sure proper versions of ffmpeg or gstreamer is installed. Sometimes, it is a headache to work with Video Capture mostly due to wrong installation of ffmpeg/gstreamer. - - -Saving a Video -================ - -So we capture a video, process it frame-by-frame and we want to save that video. For images, it is very simple, just use ``cv2.imwrite()``. Here a little more work is required. - -This time we create a **VideoWriter** object. We should specify the output file name (eg: output.avi). Then we should specify the **FourCC** code (details in next paragraph). Then number of frames per second (fps) and frame size should be passed. And last one is **isColor** flag. If it is True, encoder expect color frame, otherwise it works with grayscale frame. - -`FourCC `_ is a 4-byte code used to specify the video codec. The list of available codes can be found in `fourcc.org `_. It is platform dependent. Following codecs works fine for me. - -* In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID is more preferable. MJPG results in high size video. X264 gives very small size video) -* In Windows: DIVX (More to be tested and added) -* In OSX : *(I don't have access to OSX. Can some one fill this?)* - -FourCC code is passed as ``cv2.VideoWriter_fourcc('M','J','P','G')`` or ``cv2.VideoWriter_fourcc(*'MJPG)`` for MJPG. - -Below code capture from a Camera, flip every frame in vertical direction and saves it. -:: - - import numpy as np - import cv2 - - cap = cv2.VideoCapture(0) - - # Define the codec and create VideoWriter object - fourcc = cv2.VideoWriter_fourcc(*'XVID') - out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480)) - - while(cap.isOpened()): - ret, frame = cap.read() - if ret==True: - frame = cv2.flip(frame,0) - - # write the flipped frame - out.write(frame) - - cv2.imshow('frame',frame) - if cv2.waitKey(1) & 0xFF == ord('q'): - break - else: - break - - # Release everything if job is finished - cap.release() - out.release() - cv2.destroyAllWindows() - - -Additional Resources -========================== - -Exercises -================= diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/blurring.jpg b/doc/py_tutorials/py_imgproc/images/blurring.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/blurring.jpg rename to doc/py_tutorials/py_imgproc/images/blurring.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/canny.jpg b/doc/py_tutorials/py_imgproc/images/canny.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/canny.jpg rename to doc/py_tutorials/py_imgproc/images/canny.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/colorspace.jpg b/doc/py_tutorials/py_imgproc/images/colorspace.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/colorspace.jpg rename to doc/py_tutorials/py_imgproc/images/colorspace.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/contours.jpg b/doc/py_tutorials/py_imgproc/images/contours.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/contours.jpg rename to doc/py_tutorials/py_imgproc/images/contours.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/geometric.jpg b/doc/py_tutorials/py_imgproc/images/geometric.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/geometric.jpg rename to doc/py_tutorials/py_imgproc/images/geometric.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/grabcut.jpg b/doc/py_tutorials/py_imgproc/images/grabcut.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/grabcut.jpg rename to doc/py_tutorials/py_imgproc/images/grabcut.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/gradient.jpg b/doc/py_tutorials/py_imgproc/images/gradient.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/gradient.jpg rename to doc/py_tutorials/py_imgproc/images/gradient.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/histogram.jpg b/doc/py_tutorials/py_imgproc/images/histogram.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/histogram.jpg rename to doc/py_tutorials/py_imgproc/images/histogram.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/houghcircles.jpg b/doc/py_tutorials/py_imgproc/images/houghcircles.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/houghcircles.jpg rename to doc/py_tutorials/py_imgproc/images/houghcircles.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/houghlines.jpg b/doc/py_tutorials/py_imgproc/images/houghlines.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/houghlines.jpg rename to doc/py_tutorials/py_imgproc/images/houghlines.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/morphology.jpg b/doc/py_tutorials/py_imgproc/images/morphology.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/morphology.jpg rename to doc/py_tutorials/py_imgproc/images/morphology.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/pyramid.png b/doc/py_tutorials/py_imgproc/images/pyramid.png similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/pyramid.png rename to doc/py_tutorials/py_imgproc/images/pyramid.png diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/template.jpg b/doc/py_tutorials/py_imgproc/images/template.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/template.jpg rename to doc/py_tutorials/py_imgproc/images/template.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/thresh.jpg b/doc/py_tutorials/py_imgproc/images/thresh.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/thresh.jpg rename to doc/py_tutorials/py_imgproc/images/thresh.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/transforms.jpg b/doc/py_tutorials/py_imgproc/images/transforms.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/transforms.jpg rename to doc/py_tutorials/py_imgproc/images/transforms.jpg diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/watershed.jpg b/doc/py_tutorials/py_imgproc/images/watershed.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/images/watershed.jpg rename to doc/py_tutorials/py_imgproc/images/watershed.jpg diff --git a/doc/py_tutorials/py_imgproc/py_canny/py_canny.rst b/doc/py_tutorials/py_imgproc/py_canny/py_canny.rst deleted file mode 100644 index 75c5532626..0000000000 --- a/doc/py_tutorials/py_imgproc/py_canny/py_canny.rst +++ /dev/null @@ -1,97 +0,0 @@ -.. _Canny: - -Canny Edge Detection -*********************** - -Goal -====== - -In this chapter, we will learn about - - * Concept of Canny edge detection - * OpenCV functions for that : **cv2.Canny()** - -Theory -========= - -Canny Edge Detection is a popular edge detection algorithm. It was developed by John F. Canny in 1986. It is a multi-stage algorithm and we will go through each stages. - -1. **Noise Reduction** - -Since edge detection is susceptible to noise in the image, first step is to remove the noise in the image with a 5x5 Gaussian filter. We have already seen this in previous chapters. - -2. **Finding Intensity Gradient of the Image** - -Smoothened image is then filtered with a Sobel kernel in both horizontal and vertical direction to get first derivative in horizontal direction (:math:`G_x`) and vertical direction (:math:`G_y`). From these two images, we can find edge gradient and direction for each pixel as follows: - -.. math:: - - Edge\_Gradient \; (G) = \sqrt{G_x^2 + G_y^2} - - Angle \; (\theta) = \tan^{-1} \bigg(\frac{G_y}{G_x}\bigg) - -Gradient direction is always perpendicular to edges. It is rounded to one of four angles representing vertical, horizontal and two diagonal directions. - -3. **Non-maximum Suppression** - -After getting gradient magnitude and direction, a full scan of image is done to remove any unwanted pixels which may not constitute the edge. For this, at every pixel, pixel is checked if it is a local maximum in its neighborhood in the direction of gradient. Check the image below: - - .. image:: images/nms.jpg - :alt: Non-Maximum Suppression - :align: center - -Point A is on the edge ( in vertical direction). Gradient direction is normal to the edge. Point B and C are in gradient directions. So point A is checked with point B and C to see if it forms a local maximum. If so, it is considered for next stage, otherwise, it is suppressed ( put to zero). - -In short, the result you get is a binary image with "thin edges". - -4. **Hysteresis Thresholding** - -This stage decides which are all edges are really edges and which are not. For this, we need two threshold values, `minVal` and `maxVal`. Any edges with intensity gradient more than `maxVal` are sure to be edges and those below `minVal` are sure to be non-edges, so discarded. Those who lie between these two thresholds are classified edges or non-edges based on their connectivity. If they are connected to "sure-edge" pixels, they are considered to be part of edges. Otherwise, they are also discarded. See the image below: - - .. image:: images/hysteresis.jpg - :alt: Hysteresis Thresholding - :align: center - -The edge A is above the `maxVal`, so considered as "sure-edge". Although edge C is below `maxVal`, it is connected to edge A, so that also considered as valid edge and we get that full curve. But edge B, although it is above `minVal` and is in same region as that of edge C, it is not connected to any "sure-edge", so that is discarded. So it is very important that we have to select `minVal` and `maxVal` accordingly to get the correct result. - -This stage also removes small pixels noises on the assumption that edges are long lines. - -So what we finally get is strong edges in the image. - -Canny Edge Detection in OpenCV -=============================== - -OpenCV puts all the above in single function, **cv2.Canny()**. We will see how to use it. First argument is our input image. Second and third arguments are our `minVal` and `maxVal` respectively. Third argument is `aperture_size`. It is the size of Sobel kernel used for find image gradients. By default it is 3. Last argument is `L2gradient` which specifies the equation for finding gradient magnitude. If it is ``True``, it uses the equation mentioned above which is more accurate, otherwise it uses this function: :math:`Edge\_Gradient \; (G) = |G_x| + |G_y|`. By default, it is ``False``. -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('messi5.jpg',0) - edges = cv2.Canny(img,100,200) - - plt.subplot(121),plt.imshow(img,cmap = 'gray') - plt.title('Original Image'), plt.xticks([]), plt.yticks([]) - plt.subplot(122),plt.imshow(edges,cmap = 'gray') - plt.title('Edge Image'), plt.xticks([]), plt.yticks([]) - - plt.show() - -See the result below: - - .. image:: images/canny1.jpg - :alt: Canny Edge Detection - :align: center - -Additional Resources -======================= - -#. Canny edge detector at `Wikipedia `_ -#. `Canny Edge Detection Tutorial `_ by Bill Green, 2002. - - -Exercises -=========== - -#. Write a small application to find the Canny edge detection whose threshold values can be varied using two trackbars. This way, you can understand the effect of threshold values. diff --git a/doc/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.rst b/doc/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.rst deleted file mode 100644 index 88c41b8e9e..0000000000 --- a/doc/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.rst +++ /dev/null @@ -1,104 +0,0 @@ -.. _Converting_colorspaces: - -Changing Colorspaces -**************************** - -Goal -========= - - * In this tutorial, you will learn how to convert images from one color-space to another, like BGR :math:`\leftrightarrow` Gray, BGR :math:`\leftrightarrow` HSV etc. - * In addition to that, we will create an application which extracts a colored object in a video - * You will learn following functions : **cv2.cvtColor()**, **cv2.inRange()** etc. - -Changing Color-space -====================== - -There are more than 150 color-space conversion methods available in OpenCV. But we will look into only two which are most widely used ones, BGR :math:`\leftrightarrow` Gray and BGR :math:`\leftrightarrow` HSV. - -For color conversion, we use the function ``cv2.cvtColor(input_image, flag)`` where ``flag`` determines the type of conversion. - -For BGR :math:`\rightarrow` Gray conversion we use the flags ``cv2.COLOR_BGR2GRAY``. Similarly for BGR :math:`\rightarrow` HSV, we use the flag ``cv2.COLOR_BGR2HSV``. To get other flags, just run following commands in your Python terminal : -:: - - >>> import cv2 - >>> flags = [i for i in dir(cv2) if i.startswith('COLOR_')] - >>> print flags - - -.. note:: For HSV, Hue range is [0,179], Saturation range is [0,255] and Value range is [0,255]. Different softwares use different scales. So if you are comparing OpenCV values with them, you need to normalize these ranges. - -Object Tracking -================== - -Now we know how to convert BGR image to HSV, we can use this to extract a colored object. In HSV, it is more easier to represent a color than RGB color-space. In our application, we will try to extract a blue colored object. So here is the method: - - * Take each frame of the video - * Convert from BGR to HSV color-space - * We threshold the HSV image for a range of blue color - * Now extract the blue object alone, we can do whatever on that image we want. - -Below is the code which are commented in detail : -:: - - import cv2 - import numpy as np - - cap = cv2.VideoCapture(0) - - while(1): - - # Take each frame - _, frame = cap.read() - - # Convert BGR to HSV - hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) - - # define range of blue color in HSV - lower_blue = np.array([110,50,50]) - upper_blue = np.array([130,255,255]) - - # Threshold the HSV image to get only blue colors - mask = cv2.inRange(hsv, lower_blue, upper_blue) - - # Bitwise-AND mask and original image - res = cv2.bitwise_and(frame,frame, mask= mask) - - cv2.imshow('frame',frame) - cv2.imshow('mask',mask) - cv2.imshow('res',res) - k = cv2.waitKey(5) & 0xFF - if k == 27: - break - - cv2.destroyAllWindows() - -Below image shows tracking of the blue object: - - .. image:: images/frame.jpg - :width: 780 pt - :alt: Blue Object Tracking - :align: center - -.. note:: There are some noises in the image. We will see how to remove them in later chapters. - -.. note:: This is the simplest method in object tracking. Once you learn functions of contours, you can do plenty of things like find centroid of this object and use it to track the object, draw diagrams just by moving your hand in front of camera and many other funny stuffs. - -How to find HSV values to track? ------------------------------------ -This is a common question found in `stackoverflow.com `_. It is very simple and you can use the same function, `cv2.cvtColor()`. Instead of passing an image, you just pass the BGR values you want. For example, to find the HSV value of Green, try following commands in Python terminal: -:: - - >>> green = np.uint8([[[0,255,0 ]]]) - >>> hsv_green = cv2.cvtColor(green,cv2.COLOR_BGR2HSV) - >>> print hsv_green - [[[ 60 255 255]]] - -Now you take [H-10, 100,100] and [H+10, 255, 255] as lower bound and upper bound respectively. Apart from this method, you can use any image editing tools like GIMP or any online converters to find these values, but don't forget to adjust the HSV ranges. - - -Additional Resources -======================== - -Exercises -============ -#. Try to find a way to extract more than one colored objects, for eg, extract red, blue, green objects simultaneously. diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/images/contour_defects.jpg b/doc/py_tutorials/py_imgproc/py_contours/images/contour_defects.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/images/contour_defects.jpg rename to doc/py_tutorials/py_imgproc/py_contours/images/contour_defects.jpg diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/images/contour_features.jpg b/doc/py_tutorials/py_imgproc/py_contours/images/contour_features.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/images/contour_features.jpg rename to doc/py_tutorials/py_imgproc/py_contours/images/contour_features.jpg diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/images/contour_hierarchy.jpg b/doc/py_tutorials/py_imgproc/py_contours/images/contour_hierarchy.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/images/contour_hierarchy.jpg rename to doc/py_tutorials/py_imgproc/py_contours/images/contour_hierarchy.jpg diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/images/contour_properties.jpg b/doc/py_tutorials/py_imgproc/py_contours/images/contour_properties.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/images/contour_properties.jpg rename to doc/py_tutorials/py_imgproc/py_contours/images/contour_properties.jpg diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/images/contour_starting.jpg b/doc/py_tutorials/py_imgproc/py_contours/images/contour_starting.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/images/contour_starting.jpg rename to doc/py_tutorials/py_imgproc/py_contours/images/contour_starting.jpg diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.rst b/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.rst deleted file mode 100644 index 8220fb501e..0000000000 --- a/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.rst +++ /dev/null @@ -1,188 +0,0 @@ -.. _Contour_Features: - -Contour Features -****************** - -Goal -====== - -In this article, we will learn - - * To find the different features of contours, like area, perimeter, centroid, bounding box etc - * You will see plenty of functions related to contours. - -1. Moments -=========== - -Image moments help you to calculate some features like center of mass of the object, area of the object etc. Check out the wikipedia page on `Image Moments `_ - -The function **cv2.moments()** gives a dictionary of all moment values calculated. See below: -:: - - import cv2 - import numpy as np - - img = cv2.imread('star.jpg',0) - ret,thresh = cv2.threshold(img,127,255,0) - contours,hierarchy = cv2.findContours(thresh, 1, 2) - - cnt = contours[0] - M = cv2.moments(cnt) - print M - -From this moments, you can extract useful data like area, centroid etc. Centroid is given by the relations, :math:`C_x = \frac{M_{10}}{M_{00}}` and :math:`C_y = \frac{M_{01}}{M_{00}}`. This can be done as follows: -:: - - cx = int(M['m10']/M['m00']) - cy = int(M['m01']/M['m00']) - - -2. Contour Area -================= - -Contour area is given by the function **cv2.contourArea()** or from moments, **M['m00']**. -:: - - area = cv2.contourArea(cnt) - -3. Contour Perimeter -======================= - -It is also called arc length. It can be found out using **cv2.arcLength()** function. Second argument specify whether shape is a closed contour (if passed ``True``), or just a curve. -:: - - perimeter = cv2.arcLength(cnt,True) - -4. Contour Approximation -========================= - -It approximates a contour shape to another shape with less number of vertices depending upon the precision we specify. It is an implementation of `Douglas-Peucker algorithm `_. Check the wikipedia page for algorithm and demonstration. - -To understand this, suppose you are trying to find a square in an image, but due to some problems in the image, you didn't get a perfect square, but a "bad shape" (As shown in first image below). Now you can use this function to approximate the shape. In this, second argument is called ``epsilon``, which is maximum distance from contour to approximated contour. It is an accuracy parameter. A wise selection of ``epsilon`` is needed to get the correct output. -:: - - epsilon = 0.1*cv2.arcLength(cnt,True) - approx = cv2.approxPolyDP(cnt,epsilon,True) - -Below, in second image, green line shows the approximated curve for ``epsilon = 10% of arc length``. Third image shows the same for ``epsilon = 1% of the arc length``. Third argument specifies whether curve is closed or not. - - .. image:: images/approx.jpg - :alt: Contour Approximation - :align: center - -5. Convex Hull -================= - -Convex Hull will look similar to contour approximation, but it is not (Both may provide same results in some cases). Here, **cv2.convexHull()** function checks a curve for convexity defects and corrects it. Generally speaking, convex curves are the curves which are always bulged out, or at-least flat. And if it is bulged inside, it is called convexity defects. For example, check the below image of hand. Red line shows the convex hull of hand. The double-sided arrow marks shows the convexity defects, which are the local maximum deviations of hull from contours. - - .. image:: images/convexitydefects.jpg - :alt: Convex Hull - :align: center - -There is a little bit things to discuss about it its syntax: -:: - - hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints]] - -Arguments details: - - * **points** are the contours we pass into. - * **hull** is the output, normally we avoid it. - * **clockwise** : Orientation flag. If it is ``True``, the output convex hull is oriented clockwise. Otherwise, it is oriented counter-clockwise. - * **returnPoints** : By default, ``True``. Then it returns the coordinates of the hull points. If ``False``, it returns the indices of contour points corresponding to the hull points. - -So to get a convex hull as in above image, following is sufficient: -:: - - hull = cv2.convexHull(cnt) - -But if you want to find convexity defects, you need to pass ``returnPoints = False``. To understand it, we will take the rectangle image above. First I found its contour as ``cnt``. Now I found its convex hull with ``returnPoints = True``, I got following values: ``[[[234 202]], [[ 51 202]], [[ 51 79]], [[234 79]]]`` which are the four corner points of rectangle. Now if do the same with ``returnPoints = False``, I get following result: ``[[129],[ 67],[ 0],[142]]``. These are the indices of corresponding points in contours. For eg, check the first value: ``cnt[129] = [[234, 202]]`` which is same as first result (and so on for others). - -You will see it again when we discuss about convexity defects. - -6. Checking Convexity -========================= -There is a function to check if a curve is convex or not, **cv2.isContourConvex()**. It just return whether True or False. Not a big deal. -:: - - k = cv2.isContourConvex(cnt) - -7. Bounding Rectangle -====================== -There are two types of bounding rectangles. - -7.a. Straight Bounding Rectangle ----------------------------------- -It is a straight rectangle, it doesn't consider the rotation of the object. So area of the bounding rectangle won't be minimum. It is found by the function **cv2.boundingRect()**. - -Let (x,y) be the top-left coordinate of the rectangle and (w,h) be its width and height. -:: - - x,y,w,h = cv2.boundingRect(cnt) - cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) - -7.b. Rotated Rectangle ------------------------ -Here, bounding rectangle is drawn with minimum area, so it considers the rotation also. The function used is **cv2.minAreaRect()**. It returns a Box2D structure which contains following detals - ( center (x,y), (width, height), angle of rotation ). But to draw this rectangle, we need 4 corners of the rectangle. It is obtained by the function **cv2.boxPoints()** -:: - - rect = cv2.minAreaRect(cnt) - box = cv2.boxPoints(rect) - box = np.int0(box) - cv2.drawContours(img,[box],0,(0,0,255),2) - -Both the rectangles are shown in a single image. Green rectangle shows the normal bounding rect. Red rectangle is the rotated rect. - - .. image:: images/boundingrect.png - :alt: Bounding Rectangle - :align: center - -8. Minimum Enclosing Circle -=============================== -Next we find the circumcircle of an object using the function **cv2.minEnclosingCircle()**. It is a circle which completely covers the object with minimum area. -:: - - (x,y),radius = cv2.minEnclosingCircle(cnt) - center = (int(x),int(y)) - radius = int(radius) - cv2.circle(img,center,radius,(0,255,0),2) - -.. image:: images/circumcircle.png - :alt: Minimum Enclosing Circle - :align: center - -9. Fitting an Ellipse -========================= - -Next one is to fit an ellipse to an object. It returns the rotated rectangle in which the ellipse is inscribed. -:: - - ellipse = cv2.fitEllipse(cnt) - cv2.ellipse(img,ellipse,(0,255,0),2) - -.. image:: images/fitellipse.png - :alt: Fitting an Ellipse - :align: center - - -10. Fitting a Line -======================= - -Similarly we can fit a line to a set of points. Below image contains a set of white points. We can approximate a straight line to it. -:: - - rows,cols = img.shape[:2] - [vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01) - lefty = int((-x*vy/vx) + y) - righty = int(((cols-x)*vy/vx)+y) - cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2) - -.. image:: images/fitline.jpg - :alt: Fitting a Line - :align: center - -Additional Resources -====================== - -Exercises -============= diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contour_properties/py_contour_properties.rst b/doc/py_tutorials/py_imgproc/py_contours/py_contour_properties/py_contour_properties.rst deleted file mode 100644 index 012fb43afb..0000000000 --- a/doc/py_tutorials/py_imgproc/py_contours/py_contour_properties/py_contour_properties.rst +++ /dev/null @@ -1,126 +0,0 @@ -.. _Contour_Properties: - -Contour Properties -********************* - -Here we will learn to extract some frequently used properties of objects like Solidity, Equivalent Diameter, Mask image, Mean Intensity etc. More features can be found at `Matlab regionprops documentation `_. - -*(NB : Centroid, Area, Perimeter etc also belong to this category, but we have seen it in last chapter)* - -1. Aspect Ratio -================ - -It is the ratio of width to height of bounding rect of the object. - -.. math:: - - Aspect \; Ratio = \frac{Width}{Height} - -.. code-block:: python - - x,y,w,h = cv2.boundingRect(cnt) - aspect_ratio = float(w)/h - -2. Extent -========== - -Extent is the ratio of contour area to bounding rectangle area. - -.. math:: - Extent = \frac{Object \; Area}{Bounding \; Rectangle \; Area} - -.. code-block:: python - - area = cv2.contourArea(cnt) - x,y,w,h = cv2.boundingRect(cnt) - rect_area = w*h - extent = float(area)/rect_area - -3. Solidity -============ - -Solidity is the ratio of contour area to its convex hull area. - -.. math:: - Solidity = \frac{Contour \; Area}{Convex \; Hull \; Area} - -.. code-block:: python - - area = cv2.contourArea(cnt) - hull = cv2.convexHull(cnt) - hull_area = cv2.contourArea(hull) - solidity = float(area)/hull_area - -4. Equivalent Diameter -======================= - -Equivalent Diameter is the diameter of the circle whose area is same as the contour area. - -.. math:: - Equivalent \; Diameter = \sqrt{\frac{4 \times Contour \; Area}{\pi}} - -.. code-block:: python - - area = cv2.contourArea(cnt) - equi_diameter = np.sqrt(4*area/np.pi) - -5. Orientation -================ - -Orientation is the angle at which object is directed. Following method also gives the Major Axis and Minor Axis lengths. -:: - - (x,y),(MA,ma),angle = cv2.fitEllipse(cnt) - -6. Mask and Pixel Points -========================= - -In some cases, we may need all the points which comprises that object. It can be done as follows: -:: - - mask = np.zeros(imgray.shape,np.uint8) - cv2.drawContours(mask,[cnt],0,255,-1) - pixelpoints = np.transpose(np.nonzero(mask)) - #pixelpoints = cv2.findNonZero(mask) - -Here, two methods, one using Numpy functions, next one using OpenCV function (last commented line) are given to do the same. Results are also same, but with a slight difference. Numpy gives coordinates in **(row, column)** format, while OpenCV gives coordinates in **(x,y)** format. So basically the answers will be interchanged. Note that, **row = x** and **column = y**. - -7. Maximum Value, Minimum Value and their locations -======================================================= - -We can find these parameters using a mask image. -:: - - min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask) - -8. Mean Color or Mean Intensity -=================================== - -Here, we can find the average color of an object. Or it can be average intensity of the object in grayscale mode. We again use the same mask to do it. -:: - - mean_val = cv2.mean(im,mask = mask) - -9. Extreme Points -================== - -Extreme Points means topmost, bottommost, rightmost and leftmost points of the object. -:: - - leftmost = tuple(cnt[cnt[:,:,0].argmin()][0]) - rightmost = tuple(cnt[cnt[:,:,0].argmax()][0]) - topmost = tuple(cnt[cnt[:,:,1].argmin()][0]) - bottommost = tuple(cnt[cnt[:,:,1].argmax()][0]) - -For eg, if I apply it to an Indian map, I get the following result : - - .. image:: images/extremepoints.jpg - :alt: Extreme Points - :align: center - -Additional Resources -====================== - -Exercises -=========== -#. There are still some features left in matlab regionprops doc. Try to implement them. diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.rst b/doc/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.rst deleted file mode 100644 index 4941236762..0000000000 --- a/doc/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.rst +++ /dev/null @@ -1,80 +0,0 @@ -.. _Contours_Getting_Started: - -Contours : Getting Started -**************************** - -Goal -====== - - * Understand what contours are. - * Learn to find contours, draw contours etc - * You will see these functions : **cv2.findContours()**, **cv2.drawContours()** - -What are contours? -=================== - -Contours can be explained simply as a curve joining all the continuous points (along the boundary), having same color or intensity. The contours are a useful tool for shape analysis and object detection and recognition. - - * For better accuracy, use binary images. So before finding contours, apply threshold or canny edge detection. - * findContours function modifies the source image. So if you want source image even after finding contours, already store it to some other variables. - * In OpenCV, finding contours is like finding white object from black background. So remember, object to be found should be white and background should be black. - -Let's see how to find contours of a binary image: -:: - - import numpy as np - import cv2 - - im = cv2.imread('test.jpg') - imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) - ret,thresh = cv2.threshold(imgray,127,255,0) - contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) - -See, there are three arguments in **cv2.findContours()** function, first one is source image, second is contour retrieval mode, third is contour approximation method. And it outputs the contours and hierarchy. ``contours`` is a Python list of all the contours in the image. Each individual contour is a Numpy array of (x,y) coordinates of boundary points of the object. - -.. note:: We will discuss second and third arguments and about hierarchy in details later. Until then, the values given to them in code sample will work fine for all images. - - -How to draw the contours? -=========================== - -To draw the contours, ``cv2.drawContours`` function is used. It can also be used to draw any shape provided you have its boundary points. Its first argument is source image, second argument is the contours which should be passed as a Python list, third argument is index of contours (useful when drawing individual contour. To draw all contours, pass -1) and remaining arguments are color, thickness etc. - -To draw all the contours in an image: -:: - - cv2.drawContours(img, contours, -1, (0,255,0), 3) - -To draw an individual contour, say 4th contour: -:: - - cv2.drawContours(img, contours, 3, (0,255,0), 3) - -But most of the time, below method will be useful: -:: - - cnt = contours[4] - cv2.drawContours(img, [cnt], 0, (0,255,0), 3) - -.. note:: Last two methods are same, but when you go forward, you will see last one is more useful. - -Contour Approximation Method -================================ - -This is the third argument in ``cv2.findContours`` function. What does it denote actually? - -Above, we told that contours are the boundaries of a shape with same intensity. It stores the (x,y) coordinates of the boundary of a shape. But does it store all the coordinates ? That is specified by this contour approximation method. - -If you pass ``cv2.CHAIN_APPROX_NONE``, all the boundary points are stored. But actually do we need all the points? For eg, you found the contour of a straight line. Do you need all the points on the line to represent that line? No, we need just two end points of that line. This is what ``cv2.CHAIN_APPROX_SIMPLE`` does. It removes all redundant points and compresses the contour, thereby saving memory. - -Below image of a rectangle demonstrate this technique. Just draw a circle on all the coordinates in the contour array (drawn in blue color). First image shows points I got with ``cv2.CHAIN_APPROX_NONE`` (734 points) and second image shows the one with ``cv2.CHAIN_APPROX_SIMPLE`` (only 4 points). See, how much memory it saves!!! - - .. image:: images/none.jpg - :alt: Contour Retrieval Method - :align: center - -Additional Resources -======================== - -Exercises -============= diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contours_hierarchy/py_contours_hierarchy.rst b/doc/py_tutorials/py_imgproc/py_contours/py_contours_hierarchy/py_contours_hierarchy.rst deleted file mode 100644 index 141fd458e0..0000000000 --- a/doc/py_tutorials/py_imgproc/py_contours/py_contours_hierarchy/py_contours_hierarchy.rst +++ /dev/null @@ -1,177 +0,0 @@ -.. _Contours_Hierarchy: - -Contours Hierarchy -************************* - -Goal -======= - -This time, we learn about the hierarchy of contours, i.e. the parent-child relationship in Contours. - -Theory -========= - -In the last few articles on contours, we have worked with several functions related to contours provided by OpenCV. But when we found the contours in image using **cv2.findContours()** function, we have passed an argument, **Contour Retrieval Mode**. We usually passed **cv2.RETR_LIST** or **cv2.RETR_TREE** and it worked nice. But what does it actually mean ? - -Also, in the output, we got three arrays, first is the image, second is our contours, and one more output which we named as **hierarchy** (Please checkout the codes in previous articles). But we never used this hierarchy anywhere. Then what is this hierarchy and what is it for ? What is its relationship with the previous mentioned function argument ? - -That is what we are going to deal in this article. - -What is Hierarchy? -------------------- - -Normally we use the **cv2.findContours()** function to detect objects in an image, right ? Sometimes objects are in different locations. But in some cases, some shapes are inside other shapes. Just like nested figures. In this case, we call outer one as **parent** and inner one as **child**. This way, contours in an image has some relationship to each other. And we can specify how one contour is connected to each other, like, is it child of some other contour, or is it a parent etc. Representation of this relationship is called the **Hierarchy**. - -Consider an example image below : - - .. image:: images/hierarchy.png - :alt: Hierarchy Representation - :align: center - -In this image, there are a few shapes which I have numbered from **0-5**. *2 and 2a* denotes the external and internal contours of the outermost box. - -Here, contours 0,1,2 are **external or outermost**. We can say, they are in **hierarchy-0** or simply they are in **same hierarchy level**. - -Next comes **contour-2a**. It can be considered as a **child of contour-2** (or in opposite way, contour-2 is parent of contour-2a). So let it be in **hierarchy-1**. Similarly contour-3 is child of contour-2 and it comes in next hierarchy. Finally contours 4,5 are the children of contour-3a, and they come in the last hierarchy level. From the way I numbered the boxes, I would say contour-4 is the first child of contour-3a (It can be contour-5 also). - -I mentioned these things to understand terms like **same hierarchy level**, **external contour**, **child contour**, **parent contour**, **first child** etc. Now let's get into OpenCV. - -Hierarchy Representation in OpenCV ------------------------------------- - -So each contour has its own information regarding what hierarchy it is, who is its child, who is its parent etc. OpenCV represents it as an array of four values : **[Next, Previous, First_Child, Parent]** - -.. centered:: *"Next denotes next contour at the same hierarchical level."* - -For eg, take contour-0 in our picture. Who is next contour in its same level ? It is contour-1. So simply put ``Next = 1``. Similarly for Contour-1, next is contour-2. So ``Next = 2``. - -What about contour-2? There is no next contour in the same level. So simply, put ``Next = -1``. What about contour-4? It is in same level with contour-5. So its next contour is contour-5, so ``Next = 5``. - -.. centered:: *"Previous denotes previous contour at the same hierarchical level."* - -It is same as above. Previous contour of contour-1 is contour-0 in the same level. Similarly for contour-2, it is contour-1. And for contour-0, there is no previous, so put it as -1. - -.. centered:: *"First_Child denotes its first child contour."* - -There is no need of any explanation. For contour-2, child is contour-2a. So it gets the corresponding index value of contour-2a. What about contour-3a? It has two children. But we take only first child. And it is contour-4. So ``First_Child = 4`` for contour-3a. - -.. centered:: *"Parent denotes index of its parent contour."* - -It is just opposite of **First_Child**. Both for contour-4 and contour-5, parent contour is contour-3a. For contour-3a, it is contour-3 and so on. - -.. note:: If there is no child or parent, that field is taken as -1 - -So now we know about the hierarchy style used in OpenCV, we can check into Contour Retrieval Modes in OpenCV with the help of same image given above. ie what do flags like cv2.RETR_LIST, cv2.RETR_TREE, cv2.RETR_CCOMP, cv2.RETR_EXTERNAL etc mean? - -Contour Retrieval Mode -======================= - -1. RETR_LIST --------------- - -This is the simplest of the four flags (from explanation point of view). It simply retrieves all the contours, but doesn't create any parent-child relationship. **Parents and kids are equal under this rule, and they are just contours**. ie they all belongs to same hierarchy level. - -So here, 3rd and 4th term in hierarchy array is always -1. But obviously, Next and Previous terms will have their corresponding values. Just check it yourself and verify it. - -Below is the result I got, and each row is hierarchy details of corresponding contour. For eg, first row corresponds to contour 0. Next contour is contour 1. So Next = 1. There is no previous contour, so Previous = 0. And the remaining two, as told before, it is -1. -:: - - >>> hierarchy - array([[[ 1, -1, -1, -1], - [ 2, 0, -1, -1], - [ 3, 1, -1, -1], - [ 4, 2, -1, -1], - [ 5, 3, -1, -1], - [ 6, 4, -1, -1], - [ 7, 5, -1, -1], - [-1, 6, -1, -1]]]) - -This is the good choice to use in your code, if you are not using any hierarchy features. - -2. RETR_EXTERNAL ------------------- - -If you use this flag, it returns only extreme outer flags. All child contours are left behind. **We can say, under this law, Only the eldest in every family is taken care of. It doesn't care about other members of the family :)**. - -So, in our image, how many extreme outer contours are there? ie at hierarchy-0 level?. Only 3, ie contours 0,1,2, right? Now try to find the contours using this flag. Here also, values given to each element is same as above. Compare it with above result. Below is what I got : -:: - - >>> hierarchy - array([[[ 1, -1, -1, -1], - [ 2, 0, -1, -1], - [-1, 1, -1, -1]]]) - -You can use this flag if you want to extract only the outer contours. It might be useful in some cases. - -3. RETR_CCOMP ------------------- - -This flag retrieves all the contours and arranges them to a 2-level hierarchy. ie external contours of the object (ie its boundary) are placed in hierarchy-1. And the contours of holes inside object (if any) is placed in hierarchy-2. If any object inside it, its contour is placed again in hierarchy-1 only. And its hole in hierarchy-2 and so on. - -Just consider the image of a "big white zero" on a black background. Outer circle of zero belongs to first hierarchy, and inner circle of zero belongs to second hierarchy. - -We can explain it with a simple image. Here I have labelled the order of contours in red color and the hierarchy they belongs to, in green color (either 1 or 2). The order is same as the order OpenCV detects contours. - - .. image:: images/ccomp_hierarchy.png - :alt: CCOMP Hierarchy - :align: center - -So consider first contour, ie contour-0. It is hierarchy-1. It has two holes, contours 1&2, and they belong to hierarchy-2. So for contour-0, Next contour in same hierarchy level is contour-3. And there is no previous one. And its first is child is contour-1 in hierarchy-2. It has no parent, because it is in hierarchy-1. So its hierarchy array is [3,-1,1,-1] - -Now take contour-1. It is in hierarchy-2. Next one in same hierarchy (under the parenthood of contour-1) is contour-2. No previous one. No child, but parent is contour-0. So array is [2,-1,-1,0]. - -Similarly contour-2 : It is in hierarchy-2. There is not next contour in same hierarchy under contour-0. So no Next. Previous is contour-1. No child, parent is contour-0. So array is [-1,1,-1,0]. - -Contour - 3 : Next in hierarchy-1 is contour-5. Previous is contour-0. Child is contour-4 and no parent. So array is [5,0,4,-1]. - -Contour - 4 : It is in hierarchy 2 under contour-3 and it has no sibling. So no next, no previous, no child, parent is contour-3. So array is [-1,-1,-1,3]. - -Remaining you can fill up. This is the final answer I got: -:: - - >>> hierarchy - array([[[ 3, -1, 1, -1], - [ 2, -1, -1, 0], - [-1, 1, -1, 0], - [ 5, 0, 4, -1], - [-1, -1, -1, 3], - [ 7, 3, 6, -1], - [-1, -1, -1, 5], - [ 8, 5, -1, -1], - [-1, 7, -1, -1]]]) - - -4. RETR_TREE ------------------- - -And this is the final guy, Mr.Perfect. It retrieves all the contours and creates a full family hierarchy list. **It even tells, who is the grandpa, father, son, grandson and even beyond... :)**. - -For examle, I took above image, rewrite the code for cv2.RETR_TREE, reorder the contours as per the result given by OpenCV and analyze it. Again, red letters give the contour number and green letters give the hierarchy order. - - .. image:: images/tree_hierarchy.png - :alt: CCOMP Hierarchy - :align: center - -Take contour-0 : It is in hierarchy-0. Next contour in same hierarchy is contour-7. No previous contours. Child is contour-1. And no parent. So array is [7,-1,1,-1]. - -Take contour-2 : It is in hierarchy-1. No contour in same level. No previous one. Child is contour-2. Parent is contour-0. So array is [-1,-1,2,0]. - -And remaining, try yourself. Below is the full answer: -:: - - >>> hierarchy - array([[[ 7, -1, 1, -1], - [-1, -1, 2, 0], - [-1, -1, 3, 1], - [-1, -1, 4, 2], - [-1, -1, 5, 3], - [ 6, -1, -1, 4], - [-1, 5, -1, 4], - [ 8, 0, -1, -1], - [-1, 7, -1, -1]]]) - -Additional Resources -======================= - -Exercises -========== diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.rst b/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.rst deleted file mode 100644 index ad17a00042..0000000000 --- a/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.rst +++ /dev/null @@ -1,122 +0,0 @@ -.. _Contours_More_Functions: - -Contours : More Functions -****************************** - -Goal -====== - -In this chapter, we will learn about - * Convexity defects and how to find them. - * Finding shortest distance from a point to a polygon - * Matching different shapes - -Theory and Code -================ - -1. Convexity Defects ------------------------ - -We saw what is convex hull in second chapter about contours. Any deviation of the object from this hull can be considered as convexity defect. - -OpenCV comes with a ready-made function to find this, **cv2.convexityDefects()**. A basic function call would look like below: -:: - - hull = cv2.convexHull(cnt,returnPoints = False) - defects = cv2.convexityDefects(cnt,hull) - -.. note:: Remember we have to pass ``returnPoints = False`` while finding convex hull, in order to find convexity defects. - -It returns an array where each row contains these values - **[ start point, end point, farthest point, approximate distance to farthest point ]**. We can visualize it using an image. We draw a line joining start point and end point, then draw a circle at the farthest point. Remember first three values returned are indices of ``cnt``. So we have to bring those values from ``cnt``. -:: - - import cv2 - import numpy as np - - img = cv2.imread('star.jpg') - img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - ret, thresh = cv2.threshold(img_gray, 127, 255,0) - contours,hierarchy = cv2.findContours(thresh,2,1) - cnt = contours[0] - - hull = cv2.convexHull(cnt,returnPoints = False) - defects = cv2.convexityDefects(cnt,hull) - - for i in range(defects.shape[0]): - s,e,f,d = defects[i,0] - start = tuple(cnt[s][0]) - end = tuple(cnt[e][0]) - far = tuple(cnt[f][0]) - cv2.line(img,start,end,[0,255,0],2) - cv2.circle(img,far,5,[0,0,255],-1) - - cv2.imshow('img',img) - cv2.waitKey(0) - cv2.destroyAllWindows() - -And see the result: - - .. image:: images/defects.jpg - :alt: Convexity Defects - :align: center - -2. Point Polygon Test ------------------------ - -This function finds the shortest distance between a point in the image and a contour. It returns the distance which is negative when point is outside the contour, positive when point is inside and zero if point is on the contour. - -For example, we can check the point (50,50) as follows: -:: - - dist = cv2.pointPolygonTest(cnt,(50,50),True) - -In the function, third argument is ``measureDist``. If it is ``True``, it finds the signed distance. If ``False``, it finds whether the point is inside or outside or on the contour (it returns +1, -1, 0 respectively). - -.. note:: If you don't want to find the distance, make sure third argument is ``False``, because, it is a time consuming process. So, making it ``False`` gives about 2-3X speedup. - -3. Match Shapes ------------------ - -OpenCV comes with a function **cv2.matchShapes()** which enables us to compare two shapes, or two contours and returns a metric showing the similarity. The lower the result, the better match it is. It is calculated based on the hu-moment values. Different measurement methods are explained in the docs. -:: - - import cv2 - import numpy as np - - img1 = cv2.imread('star.jpg',0) - img2 = cv2.imread('star2.jpg',0) - - ret, thresh = cv2.threshold(img1, 127, 255,0) - ret, thresh2 = cv2.threshold(img2, 127, 255,0) - contours,hierarchy = cv2.findContours(thresh,2,1) - cnt1 = contours[0] - contours,hierarchy = cv2.findContours(thresh2,2,1) - cnt2 = contours[0] - - ret = cv2.matchShapes(cnt1,cnt2,1,0.0) - print ret - -I tried matching shapes with different shapes given below: - - .. image:: images/matchshapes.jpg - :alt: Match Shapes - :align: center - -I got following results: - - * Matching Image A with itself = 0.0 - * Matching Image A with Image B = 0.001946 - * Matching Image A with Image C = 0.326911 - -See, even image rotation doesn't affect much on this comparison. - -.. seealso:: `Hu-Moments `_ are seven moments invariant to translation, rotation and scale. Seventh one is skew-invariant. Those values can be found using **cv2.HuMoments()** function. - -Additional Resources -===================== - -Exercises -============ -#. Check the documentation for **cv2.pointPolygonTest()**, you can find a nice image in Red and Blue color. It represents the distance from all pixels to the white curve on it. All pixels inside curve is blue depending on the distance. Similarly outside points are red. Contour edges are marked with White. So problem is simple. Write a code to create such a representation of distance. - -#. Compare images of digits or letters using **cv2.matchShapes()**. ( That would be a simple step towards OCR ) diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/py_table_of_contents_contours.markdown b/doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours.markdown similarity index 100% rename from doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/py_table_of_contents_contours.markdown rename to doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours.markdown diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/py_table_of_contents_contours.rst b/doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/py_table_of_contents_contours.rst deleted file mode 100644 index de6b608c7f..0000000000 --- a/doc/py_tutorials/py_imgproc/py_contours/py_table_of_contents_contours/py_table_of_contents_contours.rst +++ /dev/null @@ -1,89 +0,0 @@ -.. _Table-Of-Content-Contours: - -Contours in OpenCV ------------------------------------------------------------ - -* :ref:`Contours_Getting_Started` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |contour_1| Learn to find and draw Contours - - - =========== =================================================================== - - .. |contour_1| image:: images/contour_starting.jpg - :height: 90pt - :width: 90pt - -* :ref:`Contour_Features` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |contour_2| Learn to find different features of contours like area, perimeter, bounding rectangle etc. - - =========== =================================================================== - - .. |contour_2| image:: images/contour_features.jpg - :height: 90pt - :width: 90pt - -* :ref:`Contour_Properties` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |contour_3| Learn to find different properties of contours like Solidity, Mean Intensity etc. - - =========== =================================================================== - - .. |contour_3| image:: images/contour_properties.jpg - :height: 90pt - :width: 90pt - -* :ref:`Contours_More_Functions` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |contour_4| Learn to find convexity defects, pointPolygonTest, match different shapes etc. - - =========== =================================================================== - - .. |contour_4| image:: images/contour_defects.jpg - :height: 90pt - :width: 90pt - -* :ref:`Contours_Hierarchy` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |contour_5| Learn about Contour Hierarchy - - =========== =================================================================== - - .. |contour_5| image:: images/contour_hierarchy.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_contours_begin/py_contours_begin - ../py_contour_features/py_contour_features - ../py_contour_properties/py_contour_properties - ../py_contours_more_functions/py_contours_more_functions - ../py_contours_hierarchy/py_contours_hierarchy diff --git a/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.rst b/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.rst deleted file mode 100644 index ccba1b1353..0000000000 --- a/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.rst +++ /dev/null @@ -1,151 +0,0 @@ -.. _Filtering: - -Smoothing Images -*********************** - -Goals -======= - -Learn to: - * Blur the images with various low pass filters - * Apply custom-made filters to images (2D convolution) - -2D Convolution ( Image Filtering ) -==================================== - -As in one-dimensional signals, images also can be filtered with various low-pass filters(LPF), high-pass filters(HPF) etc. LPF helps in removing noises, blurring the images etc. HPF filters helps in finding edges in the images. - -OpenCV provides a function **cv2.filter2D()** to convolve a kernel with an image. As an example, we will try an averaging filter on an image. A 5x5 averaging filter kernel will look like below: - -.. math:: - - K = \frac{1}{25} \begin{bmatrix} 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \end{bmatrix} - -Operation is like this: keep this kernel above a pixel, add all the 25 pixels below this kernel, take its average and replace the central pixel with the new average value. It continues this operation for all the pixels in the image. Try this code and check the result: -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('opencv_logo.png') - - kernel = np.ones((5,5),np.float32)/25 - dst = cv2.filter2D(img,-1,kernel) - - plt.subplot(121),plt.imshow(img),plt.title('Original') - plt.xticks([]), plt.yticks([]) - plt.subplot(122),plt.imshow(dst),plt.title('Averaging') - plt.xticks([]), plt.yticks([]) - plt.show() - -Result: - - .. image:: images/filter.jpg - :alt: Averaging Filter - :align: center - -Image Blurring (Image Smoothing) -================================== - -Image blurring is achieved by convolving the image with a low-pass filter kernel. It is useful for removing noises. It actually removes high frequency content (eg: noise, edges) from the image. So edges are blurred a little bit in this operation. (Well, there are blurring techniques which doesn't blur the edges too). OpenCV provides mainly four types of blurring techniques. - -1. Averaging --------------- - -This is done by convolving image with a normalized box filter. It simply takes the average of all the pixels under kernel area and replace the central element. This is done by the function **cv2.blur()** or **cv2.boxFilter()**. Check the docs for more details about the kernel. We should specify the width and height of kernel. A 3x3 normalized box filter would look like below: - -.. math:: - - K = \frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix} - -.. note:: If you don't want to use normalized box filter, use **cv2.boxFilter()**. Pass an argument ``normalize=False`` to the function. - -Check a sample demo below with a kernel of 5x5 size: -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('opencv_logo.png') - - blur = cv2.blur(img,(5,5)) - - plt.subplot(121),plt.imshow(img),plt.title('Original') - plt.xticks([]), plt.yticks([]) - plt.subplot(122),plt.imshow(blur),plt.title('Blurred') - plt.xticks([]), plt.yticks([]) - plt.show() - -Result: - - .. image:: images/blur.jpg - :alt: Averaging Filter - :align: center - - -2. Gaussian Blurring ----------------------- - -In this, instead of box filter, gaussian kernel is used. It is done with the function, **cv2.GaussianBlur()**. We should specify the width and height of kernel which should be positive and odd. We also should specify the standard deviation in X and Y direction, sigmaX and sigmaY respectively. If only sigmaX is specified, sigmaY is taken as same as sigmaX. If both are given as zeros, they are calculated from kernel size. Gaussian blurring is highly effective in removing gaussian noise from the image. - -If you want, you can create a Gaussian kernel with the function, **cv2.getGaussianKernel()**. - -The above code can be modified for Gaussian blurring: -:: - - blur = cv2.GaussianBlur(img,(5,5),0) - - -Result: - - .. image:: images/gaussian.jpg - :alt: Gaussian Blurring - :align: center - - -3. Median Blurring --------------------- - -Here, the function **cv2.medianBlur()** takes median of all the pixels under kernel area and central element is replaced with this median value. This is highly effective against salt-and-pepper noise in the images. Interesting thing is that, in the above filters, central element is a newly calculated value which may be a pixel value in the image or a new value. But in median blurring, central element is always replaced by some pixel value in the image. It reduces the noise effectively. Its kernel size should be a positive odd integer. - -In this demo, I added a 50% noise to our original image and applied median blur. Check the result: -:: - - median = cv2.medianBlur(img,5) - -Result: - - .. image:: images/median.jpg - :alt: Median Blurring - :align: center - - -4. Bilateral Filtering ------------------------ - -**cv2.bilateralFilter()** is highly effective in noise removal while keeping edges sharp. But the operation is slower compared to other filters. We already saw that gaussian filter takes the a neighbourhood around the pixel and find its gaussian weighted average. This gaussian filter is a function of space alone, that is, nearby pixels are considered while filtering. It doesn't consider whether pixels have almost same intensity. It doesn't consider whether pixel is an edge pixel or not. So it blurs the edges also, which we don't want to do. - -Bilateral filter also takes a gaussian filter in space, but one more gaussian filter which is a function of pixel difference. Gaussian function of space make sure only nearby pixels are considered for blurring while gaussian function of intensity difference make sure only those pixels with similar intensity to central pixel is considered for blurring. So it preserves the edges since pixels at edges will have large intensity variation. - -Below samples shows use bilateral filter (For details on arguments, visit docs). -:: - - blur = cv2.bilateralFilter(img,9,75,75) - -Result: - - .. image:: images/bilateral.jpg - :alt: Bilateral Filtering - :align: center - -See, the texture on the surface is gone, but edges are still preserved. - -Additional Resources -====================== - -1. Details about the `bilateral filtering `_ - -Exercises -=========== diff --git a/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.rst b/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.rst deleted file mode 100644 index 109a8395a0..0000000000 --- a/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.rst +++ /dev/null @@ -1,166 +0,0 @@ -.. _Geometric_Transformations: - -Geometric Transformations of Images -************************************* - -Goals -======== - - * Learn to apply different geometric transformation to images like translation, rotation, affine transformation etc. - * You will see these functions: **cv2.getPerspectiveTransform** - -Transformations -================= - -OpenCV provides two transformation functions, **cv2.warpAffine** and **cv2.warpPerspective**, with which you can have all kinds of transformations. **cv2.warpAffine** takes a 2x3 transformation matrix while **cv2.warpPerspective** takes a 3x3 transformation matrix as input. - -Scaling ---------- - -Scaling is just resizing of the image. OpenCV comes with a function **cv2.resize()** for this purpose. The size of the image can be specified manually, or you can specify the scaling factor. Different interpolation methods are used. Preferable interpolation methods are **cv2.INTER_AREA** for shrinking and **cv2.INTER_CUBIC** (slow) & **cv2.INTER_LINEAR** for zooming. By default, interpolation method used is **cv2.INTER_LINEAR** for all resizing purposes. You can resize an input image either of following methods: -:: - - import cv2 - import numpy as np - - img = cv2.imread('messi5.jpg') - - res = cv2.resize(img,None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC) - - #OR - - height, width = img.shape[:2] - res = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC) - -Translation -------------- - -Translation is the shifting of object's location. If you know the shift in (x,y) direction, let it be :math:`(t_x,t_y)`, you can create the transformation matrix :math:`\textbf{M}` as follows: - -.. math:: - - M = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \end{bmatrix} - -You can take make it into a Numpy array of type ``np.float32`` and pass it into **cv2.warpAffine()** function. See below example for a shift of (100,50): -:: - - import cv2 - import numpy as np - - img = cv2.imread('messi5.jpg',0) - rows,cols = img.shape - - M = np.float32([[1,0,100],[0,1,50]]) - dst = cv2.warpAffine(img,M,(cols,rows)) - - cv2.imshow('img',dst) - cv2.waitKey(0) - cv2.destroyAllWindows() - -.. warning:: Third argument of the **cv2.warpAffine()** function is the size of the output image, which should be in the form of **(width, height)**. Remember width = number of columns, and height = number of rows. - -See the result below: - - .. image:: images/translation.jpg - :alt: Translation - :align: center - -Rotation ----------- - -Rotation of an image for an angle :math:`\theta` is achieved by the transformation matrix of the form - -.. math:: - - M = \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix} - -But OpenCV provides scaled rotation with adjustable center of rotation so that you can rotate at any location you prefer. Modified transformation matrix is given by - -.. math:: - - \begin{bmatrix} \alpha & \beta & (1- \alpha ) \cdot center.x - \beta \cdot center.y \\ - \beta & \alpha & \beta \cdot center.x + (1- \alpha ) \cdot center.y \end{bmatrix} - -where: - -.. math:: - - \begin{array}{l} \alpha = scale \cdot \cos \theta , \\ \beta = scale \cdot \sin \theta \end{array} - -To find this transformation matrix, OpenCV provides a function, **cv2.getRotationMatrix2D**. Check below example which rotates the image by 90 degree with respect to center without any scaling. -:: - - img = cv2.imread('messi5.jpg',0) - rows,cols = img.shape - - M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1) - dst = cv2.warpAffine(img,M,(cols,rows)) - -See the result: - - .. image:: images/rotation.jpg - :alt: Rotation of Image - :align: center - - -Affine Transformation ------------------------- - -In affine transformation, all parallel lines in the original image will still be parallel in the output image. To find the transformation matrix, we need three points from input image and their corresponding locations in output image. Then **cv2.getAffineTransform** will create a 2x3 matrix which is to be passed to **cv2.warpAffine**. - -Check below example, and also look at the points I selected (which are marked in Green color): -:: - - img = cv2.imread('drawing.png') - rows,cols,ch = img.shape - - pts1 = np.float32([[50,50],[200,50],[50,200]]) - pts2 = np.float32([[10,100],[200,50],[100,250]]) - - M = cv2.getAffineTransform(pts1,pts2) - - dst = cv2.warpAffine(img,M,(cols,rows)) - - plt.subplot(121),plt.imshow(img),plt.title('Input') - plt.subplot(122),plt.imshow(dst),plt.title('Output') - plt.show() - -See the result: - - .. image:: images/affine.jpg - :alt: Affine Transformation - :align: center - -Perspective Transformation ----------------------------- - -For perspective transformation, you need a 3x3 transformation matrix. Straight lines will remain straight even after the transformation. To find this transformation matrix, you need 4 points on the input image and corresponding points on the output image. Among these 4 points, 3 of them should not be collinear. Then transformation matrix can be found by the function **cv2.getPerspectiveTransform**. Then apply **cv2.warpPerspective** with this 3x3 transformation matrix. - -See the code below: -:: - - img = cv2.imread('sudokusmall.png') - rows,cols,ch = img.shape - - pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]]) - pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]]) - - M = cv2.getPerspectiveTransform(pts1,pts2) - - dst = cv2.warpPerspective(img,M,(300,300)) - - plt.subplot(121),plt.imshow(img),plt.title('Input') - plt.subplot(122),plt.imshow(dst),plt.title('Output') - plt.show() - -Result: - - .. image:: images/perspective.jpg - :alt: Perspective Transformation - :align: center - -Additional Resources -===================== -#. "Computer Vision: Algorithms and Applications", Richard Szeliski - -Exercises -=========== diff --git a/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.rst b/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.rst deleted file mode 100644 index 07c23c7c6f..0000000000 --- a/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.rst +++ /dev/null @@ -1,118 +0,0 @@ -.. _grabcut: - -Interactive Foreground Extraction using GrabCut Algorithm -************************************************************* - -Goal -====== - -In this chapter - * We will see GrabCut algorithm to extract foreground in images - * We will create an interactive application for this. - -Theory -========= - -GrabCut algorithm was designed by Carsten Rother, Vladimir Kolmogorov & Andrew Blake from Microsoft Research Cambridge, UK. in their paper, `"GrabCut": interactive foreground extraction using iterated graph cuts `_ . An algorithm was needed for foreground extraction with minimal user interaction, and the result was GrabCut. - -How it works from user point of view ? Initially user draws a rectangle around the foreground region (foreground region shoule be completely inside the rectangle). Then algorithm segments it iteratively to get the best result. Done. But in some cases, the segmentation won't be fine, like, it may have marked some foreground region as background and vice versa. In that case, user need to do fine touch-ups. Just give some strokes on the images where some faulty results are there. Strokes basically says *"Hey, this region should be foreground, you marked it background, correct it in next iteration"* or its opposite for background. Then in the next iteration, you get better results. - -See the image below. First player and football is enclosed in a blue rectangle. Then some final touchups with white strokes (denoting foreground) and black strokes (denoting background) is made. And we get a nice result. - - .. image:: images/grabcut_output1.jpg - :alt: GrabCut in Action - :align: center - -So what happens in background ? - - * User inputs the rectangle. Everything outside this rectangle will be taken as sure background (That is the reason it is mentioned before that your rectangle should include all the objects). Everything inside rectangle is unknown. Similarly any user input specifying foreground and background are considered as hard-labelling which means they won't change in the process. - * Computer does an initial labelling depeding on the data we gave. It labels the foreground and background pixels (or it hard-labels) - * Now a Gaussian Mixture Model(GMM) is used to model the foreground and background. - * Depending on the data we gave, GMM learns and create new pixel distribution. That is, the unknown pixels are labelled either probable foreground or probable background depending on its relation with the other hard-labelled pixels in terms of color statistics (It is just like clustering). - * A graph is built from this pixel distribution. Nodes in the graphs are pixels. Additional two nodes are added, **Source node** and **Sink node**. Every foreground pixel is connected to Source node and every background pixel is connected to Sink node. - * The weights of edges connecting pixels to source node/end node are defined by the probability of a pixel being foreground/background. The weights between the pixels are defined by the edge information or pixel similarity. If there is a large difference in pixel color, the edge between them will get a low weight. - * Then a mincut algorithm is used to segment the graph. It cuts the graph into two separating source node and sink node with minimum cost function. The cost function is the sum of all weights of the edges that are cut. After the cut, all the pixels connected to Source node become foreground and those connected to Sink node become background. - * The process is continued until the classification converges. - -It is illustrated in below image (Image Courtesy: http://www.cs.ru.ac.za/research/g02m1682/) - - .. image:: images/grabcut_scheme.jpg - :alt: Simplified Diagram of GrabCut Algorithm - :align: center - -Demo -======= - -Now we go for grabcut algorithm with OpenCV. OpenCV has the function, **cv2.grabCut()** for this. We will see its arguments first: - - * *img* - Input image - * *mask* - It is a mask image where we specify which areas are background, foreground or probable background/foreground etc. It is done by the following flags, **cv2.GC_BGD, cv2.GC_FGD, cv2.GC_PR_BGD, cv2.GC_PR_FGD**, or simply pass 0,1,2,3 to image. - * *rect* - It is the coordinates of a rectangle which includes the foreground object in the format (x,y,w,h) - * *bdgModel*, *fgdModel* - These are arrays used by the algorithm internally. You just create two np.float64 type zero arrays of size (1,65). - * *iterCount* - Number of iterations the algorithm should run. - * *mode* - It should be **cv2.GC_INIT_WITH_RECT** or **cv2.GC_INIT_WITH_MASK** or combined which decides whether we are drawing rectangle or final touchup strokes. - -First let's see with rectangular mode. We load the image, create a similar mask image. We create *fgdModel* and *bgdModel*. We give the rectangle parameters. It's all straight-forward. Let the algorithm run for 5 iterations. Mode should be *cv2.GC_INIT_WITH_RECT* since we are using rectangle. Then run the grabcut. It modifies the mask image. In the new mask image, pixels will be marked with four flags denoting background/foreground as specified above. So we modify the mask such that all 0-pixels and 2-pixels are put to 0 (ie background) and all 1-pixels and 3-pixels are put to 1(ie foreground pixels). Now our final mask is ready. Just multiply it with input image to get the segmented image. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img = cv2.imread('messi5.jpg') - mask = np.zeros(img.shape[:2],np.uint8) - - bgdModel = np.zeros((1,65),np.float64) - fgdModel = np.zeros((1,65),np.float64) - - rect = (50,50,450,290) - cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT) - - mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8') - img = img*mask2[:,:,np.newaxis] - - plt.imshow(img),plt.colorbar(),plt.show() - -See the results below: - - .. image:: images/grabcut_rect.jpg - :alt: Segmentation in rect mode - :align: center - -Oops, Messi's hair is gone. *Who likes Messi without his hair?* We need to bring it back. So we will give there a fine touchup with 1-pixel (sure foreground). At the same time, Some part of ground has come to picture which we don't want, and also some logo. We need to remove them. There we give some 0-pixel touchup (sure background). So we modify our resulting mask in previous case as we told now. - -*What I actually did is that, I opened input image in paint application and added another layer to the image. Using brush tool in the paint, I marked missed foreground (hair, shoes, ball etc) with white and unwanted background (like logo, ground etc) with black on this new layer. Then filled remaining background with gray. Then loaded that mask image in OpenCV, edited original mask image we got with corresponding values in newly added mask image. Check the code below:* -:: - - # newmask is the mask image I manually labelled - newmask = cv2.imread('newmask.png',0) - - # whereever it is marked white (sure foreground), change mask=1 - # whereever it is marked black (sure background), change mask=0 - mask[newmask == 0] = 0 - mask[newmask == 255] = 1 - - mask, bgdModel, fgdModel = cv2.grabCut(img,mask,None,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK) - - mask = np.where((mask==2)|(mask==0),0,1).astype('uint8') - img = img*mask[:,:,np.newaxis] - plt.imshow(img),plt.colorbar(),plt.show() - -See the result below: - - .. image:: images/grabcut_mask.jpg - :alt: Segmentation in mask mode - :align: center - -So that's it. Here instead of initializing in rect mode, you can directly go into mask mode. Just mark the rectangle area in mask image with 2-pixel or 3-pixel (probable background/foreground). Then mark our sure_foreground with 1-pixel as we did in second example. Then directly apply the grabCut function with mask mode. - -Additional Resources -======================= - - - -Exercises -============ - -#. OpenCV samples contain a sample ``grabcut.py`` which is an interactive tool using grabcut. Check it. Also watch this `youtube video `_ on how to use it. -#. Here, you can make this into a interactive sample with drawing rectangle and strokes with mouse, create trackbar to adjust stroke width etc. diff --git a/doc/py_tutorials/py_imgproc/py_gradients/py_gradients.rst b/doc/py_tutorials/py_imgproc/py_gradients/py_gradients.rst deleted file mode 100644 index 138c74b548..0000000000 --- a/doc/py_tutorials/py_imgproc/py_gradients/py_gradients.rst +++ /dev/null @@ -1,107 +0,0 @@ -.. _Gradients: - -Image Gradients -********************** - -Goal -====== - -In this chapter, we will learn to: - - * Find Image gradients, edges etc - * We will see following functions : **cv2.Sobel()**, **cv2.Scharr()**, **cv2.Laplacian()** etc - -Theory -======= - -OpenCV provides three types of gradient filters or High-pass filters, Sobel, Scharr and Laplacian. We will see each one of them. - -1. Sobel and Scharr Derivatives ---------------------------------- - -Sobel operators is a joint Gausssian smoothing plus differentiation operation, so it is more resistant to noise. You can specify the direction of derivatives to be taken, vertical or horizontal (by the arguments, ``yorder`` and ``xorder`` respectively). You can also specify the size of kernel by the argument ``ksize``. If ksize = -1, a 3x3 Scharr filter is used which gives better results than 3x3 Sobel filter. Please see the docs for kernels used. - -2. Laplacian Derivatives --------------------------- - -It calculates the Laplacian of the image given by the relation, :math:`\Delta src = \frac{\partial ^2{src}}{\partial x^2} + \frac{\partial ^2{src}}{\partial y^2}` where each derivative is found using Sobel derivatives. If ``ksize = 1``, then following kernel is used for filtering: - -.. math:: - - kernel = \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{bmatrix} - -Code -======= - -Below code shows all operators in a single diagram. All kernels are of 5x5 size. Depth of output image is passed -1 to get the result in np.uint8 type. -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('dave.jpg',0) - - laplacian = cv2.Laplacian(img,cv2.CV_64F) - sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5) - sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5) - - plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray') - plt.title('Original'), plt.xticks([]), plt.yticks([]) - plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray') - plt.title('Laplacian'), plt.xticks([]), plt.yticks([]) - plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray') - plt.title('Sobel X'), plt.xticks([]), plt.yticks([]) - plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray') - plt.title('Sobel Y'), plt.xticks([]), plt.yticks([]) - - plt.show() - -Result: - - .. image:: images/gradients.jpg - :alt: Image Gradients - :align: center - -One Important Matter! -======================= - -In our last example, output datatype is cv2.CV_8U or np.uint8. But there is a slight problem with that. Black-to-White transition is taken as Positive slope (it has a positive value) while White-to-Black transition is taken as a Negative slope (It has negative value). So when you convert data to np.uint8, all negative slopes are made zero. In simple words, you miss that edge. - -If you want to detect both edges, better option is to keep the output datatype to some higher forms, like cv2.CV_16S, cv2.CV_64F etc, take its absolute value and then convert back to cv2.CV_8U. Below code demonstrates this procedure for a horizontal Sobel filter and difference in results. -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('box.png',0) - - # Output dtype = cv2.CV_8U - sobelx8u = cv2.Sobel(img,cv2.CV_8U,1,0,ksize=5) - - # Output dtype = cv2.CV_64F. Then take its absolute and convert to cv2.CV_8U - sobelx64f = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5) - abs_sobel64f = np.absolute(sobelx64f) - sobel_8u = np.uint8(abs_sobel64f) - - plt.subplot(1,3,1),plt.imshow(img,cmap = 'gray') - plt.title('Original'), plt.xticks([]), plt.yticks([]) - plt.subplot(1,3,2),plt.imshow(sobelx8u,cmap = 'gray') - plt.title('Sobel CV_8U'), plt.xticks([]), plt.yticks([]) - plt.subplot(1,3,3),plt.imshow(sobel_8u,cmap = 'gray') - plt.title('Sobel abs(CV_64F)'), plt.xticks([]), plt.yticks([]) - - plt.show() - -Check the result below: - - .. image:: images/double_edge.jpg - :alt: Double Edges - :align: center - -Additional Resources -====================== - -Exercises -=========== diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/images/histograms_1d.jpg b/doc/py_tutorials/py_imgproc/py_histograms/images/histograms_1d.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/images/histograms_1d.jpg rename to doc/py_tutorials/py_imgproc/py_histograms/images/histograms_1d.jpg diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/images/histograms_2d.jpg b/doc/py_tutorials/py_imgproc/py_histograms/images/histograms_2d.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/images/histograms_2d.jpg rename to doc/py_tutorials/py_imgproc/py_histograms/images/histograms_2d.jpg diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/images/histograms_bp.jpg b/doc/py_tutorials/py_imgproc/py_histograms/images/histograms_bp.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/images/histograms_bp.jpg rename to doc/py_tutorials/py_imgproc/py_histograms/images/histograms_bp.jpg diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/images/histograms_equ.jpg b/doc/py_tutorials/py_imgproc/py_histograms/images/histograms_equ.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/images/histograms_equ.jpg rename to doc/py_tutorials/py_imgproc/py_histograms/images/histograms_equ.jpg diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.rst b/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.rst deleted file mode 100644 index 1beab913b1..0000000000 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.rst +++ /dev/null @@ -1,112 +0,0 @@ -.. _TwoD_Histogram: - -Histograms - 3 : 2D Histograms -************************************* - -Goal -======= - -In this chapter, we will learn to find and plot 2D histograms. It will be helpful in coming chapters. - -Introduction -=============== - -In the first article, we calculated and plotted one-dimensional histogram. It is called one-dimensional because we are taking only one feature into our consideration, ie grayscale intensity value of the pixel. But in two-dimensional histograms, you consider two features. Normally it is used for finding color histograms where two features are Hue & Saturation values of every pixel. - -There is a `python sample in the official samples `_ already for finding color histograms. We will try to understand how to create such a color histogram, and it will be useful in understanding further topics like Histogram Back-Projection. - -2D Histogram in OpenCV -======================= - -It is quite simple and calculated using the same function, **cv2.calcHist()**. For color histograms, we need to convert the image from BGR to HSV. (Remember, for 1D histogram, we converted from BGR to Grayscale). For 2D histograms, its parameters will be modified as follows: - -* **channels = [0,1]** *because we need to process both H and S plane.* -* **bins = [180,256]** *180 for H plane and 256 for S plane.* -* **range = [0,180,0,256]** *Hue value lies between 0 and 180 & Saturation lies between 0 and 256.* - -Now check the code below: -:: - - import cv2 - import numpy as np - - img = cv2.imread('home.jpg') - hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) - - hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256]) - -That's it. - -2D Histogram in Numpy -======================= -Numpy also provides a specific function for this : **np.histogram2d()**. (Remember, for 1D histogram we used **np.histogram()** ). -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('home.jpg') - hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) - - hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]]) - -First argument is H plane, second one is the S plane, third is number of bins for each and fourth is their range. - -Now we can check how to plot this color histogram. - -Plotting 2D Histograms -======================== - -Method - 1 : Using cv2.imshow() ---------------------------------- -The result we get is a two dimensional array of size 180x256. So we can show them as we do normally, using cv2.imshow() function. It will be a grayscale image and it won't give much idea what colors are there, unless you know the Hue values of different colors. - -Method - 2 : Using Matplotlib ------------------------------- -We can use **matplotlib.pyplot.imshow()** function to plot 2D histogram with different color maps. It gives us a much better idea about the different pixel density. But this also, doesn't gives us idea what color is there on a first look, unless you know the Hue values of different colors. Still I prefer this method. It is simple and better. - -.. note:: While using this function, remember, interpolation flag should be ``nearest`` for better results. - -Consider code: -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('home.jpg') - hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) - hist = cv2.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] ) - - plt.imshow(hist,interpolation = 'nearest') - plt.show() - -Below is the input image and its color histogram plot. X axis shows S values and Y axis shows Hue. - - .. image:: images/2dhist_matplotlib.jpg - :alt: 2D Histograms - :align: center - -In histogram, you can see some high values near H = 100 and S = 200. It corresponds to blue of sky. Similarly another peak can be seen near H = 25 and S = 100. It corresponds to yellow of the palace. You can verify it with any image editing tools like GIMP. - -Method 3 : OpenCV sample style !! ------------------------------------- - -There is a `sample code for color-histogram in OpenCV-Python2 samples `_. If you run the code, you can see the histogram shows the corresponding color also. Or simply it outputs a color coded histogram. Its result is very good (although you need to add extra bunch of lines). - -In that code, the author created a color map in HSV. Then converted it into BGR. The resulting histogram image is multiplied with this color map. He also uses some preprocessing steps to remove small isolated pixels, resulting in a good histogram. - -I leave it to the readers to run the code, analyze it and have your own hack arounds. Below is the output of that code for the same image as above: - - .. image:: images/2dhist_opencv.jpg - :alt: 2D Histograms using OpenCV-Python Samples - :align: center - -You can clearly see in the histogram what colors are present, blue is there, yellow is there, and some white due to chessboard is there. Nice !!! - -Additional Resources -===================== - -Exercises -================ diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.rst b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.rst deleted file mode 100644 index f2fc664378..0000000000 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.rst +++ /dev/null @@ -1,111 +0,0 @@ -.. _Histogram_Backprojection: - -Histogram - 4 : Histogram Backprojection -******************************************* - -Goal -======= - -In this chapter, we will learn about histogram backprojection. - -Theory -======= - -It was proposed by **Michael J. Swain , Dana H. Ballard** in their paper **Indexing via color histograms**. - -**What is it actually in simple words?** It is used for image segmentation or finding objects of interest in an image. In simple words, it creates an image of the same size (but single channel) as that of our input image, where each pixel corresponds to the probability of that pixel belonging to our object. In more simpler worlds, the output image will have our object of interest in more white compared to remaining part. Well, that is an intuitive explanation. (I can't make it more simpler). Histogram Backprojection is used with camshift algorithm etc. - -**How do we do it ?** We create a histogram of an image containing our object of interest (in our case, the ground, leaving player and other things). The object should fill the image as far as possible for better results. And a color histogram is preferred over grayscale histogram, because color of the object is a better way to define the object than its grayscale intensity. We then "back-project" this histogram over our test image where we need to find the object, ie in other words, we calculate the probability of every pixel belonging to the ground and show it. The resulting output on proper thresholding gives us the ground alone. - -Algorithm in Numpy -==================== - -1. First we need to calculate the color histogram of both the object we need to find (let it be 'M') and the image where we are going to search (let it be 'I'). -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - #roi is the object or region of object we need to find - roi = cv2.imread('rose_red.png') - hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV) - - #target is the image we search in - target = cv2.imread('rose.png') - hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV) - - # Find the histograms using calcHist. Can be done with np.histogram2d also - M = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] ) - I = cv2.calcHist([hsvt],[0, 1], None, [180, 256], [0, 180, 0, 256] ) - -2. Find the ratio :math:`R = \frac{M}{I}`. Then backproject R, ie use R as palette and create a new image with every pixel as its corresponding probability of being target. ie ``B(x,y) = R[h(x,y),s(x,y)]`` where h is hue and s is saturation of the pixel at (x,y). After that apply the condition :math:`B(x,y) = min[B(x,y), 1]`. -:: - - h,s,v = cv2.split(hsvt) - B = R[h.ravel(),s.ravel()] - B = np.minimum(B,1) - B = B.reshape(hsvt.shape[:2]) - -3. Now apply a convolution with a circular disc, :math:`B = D \ast B`, where D is the disc kernel. -:: - - disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) - cv2.filter2D(B,-1,disc,B) - B = np.uint8(B) - cv2.normalize(B,B,0,255,cv2.NORM_MINMAX) - -4. Now the location of maximum intensity gives us the location of object. If we are expecting a region in the image, thresholding for a suitable value gives a nice result. -:: - - ret,thresh = cv2.threshold(B,50,255,0) - -That's it !! - -Backprojection in OpenCV -========================== - -OpenCV provides an inbuilt function **cv2.calcBackProject()**. Its parameters are almost same as the **cv2.calcHist()** function. One of its parameter is histogram which is histogram of the object and we have to find it. Also, the object histogram should be normalized before passing on to the backproject function. It returns the probability image. Then we convolve the image with a disc kernel and apply threshold. Below is my code and output : -:: - - import cv2 - import numpy as np - - roi = cv2.imread('rose_red.png') - hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV) - - target = cv2.imread('rose.png') - hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV) - - # calculating object histogram - roihist = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] ) - - # normalize histogram and apply backprojection - cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX) - dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1) - - # Now convolute with circular disc - disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) - cv2.filter2D(dst,-1,disc,dst) - - # threshold and binary AND - ret,thresh = cv2.threshold(dst,50,255,0) - thresh = cv2.merge((thresh,thresh,thresh)) - res = cv2.bitwise_and(target,thresh) - - res = np.vstack((target,thresh,res)) - cv2.imwrite('res.jpg',res) - -Below is one example I worked with. I used the region inside blue rectangle as sample object and I wanted to extract the full ground. - - .. image:: images/backproject_opencv.jpg - :alt: Histogram Backprojection in OpenCV - :align: center - -Additional Resources -===================== -#. "Indexing via color histograms", Swain, Michael J. , Third international conference on computer vision,1990. - - -Exercises -============ diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.rst b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.rst deleted file mode 100644 index 09377490e0..0000000000 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.rst +++ /dev/null @@ -1,169 +0,0 @@ -.. _Histograms_Getting_Started: - -Histograms - 1 : Find, Plot, Analyze !!! -****************************************** - -Goal -======= - -Learn to - * Find histograms, using both OpenCV and Numpy functions - * Plot histograms, using OpenCV and Matplotlib functions - * You will see these functions : **cv2.calcHist()**, **np.histogram()** etc. - -Theory -======== - -So what is histogram ? You can consider histogram as a graph or plot, which gives you an overall idea about the intensity distribution of an image. It is a plot with pixel values (ranging from 0 to 255, not always) in X-axis and corresponding number of pixels in the image on Y-axis. - -It is just another way of understanding the image. By looking at the histogram of an image, you get intuition about contrast, brightness, intensity distribution etc of that image. Almost all image processing tools today, provides features on histogram. Below is an image from `Cambridge in Color website `_, and I recommend you to visit the site for more details. - - .. image:: images/histogram_sample.jpg - :alt: Histogram Example - :align: center - -You can see the image and its histogram. (Remember, this histogram is drawn for grayscale image, not color image). Left region of histogram shows the amount of darker pixels in image and right region shows the amount of brighter pixels. From the histogram, you can see dark region is more than brighter region, and amount of midtones (pixel values in mid-range, say around 127) are very less. - -Find Histogram -================ - -Now we have an idea on what is histogram, we can look into how to find this. Both OpenCV and Numpy come with in-built function for this. Before using those functions, we need to understand some terminologies related with histograms. - -**BINS** :The above histogram shows the number of pixels for every pixel value, ie from 0 to 255. ie you need 256 values to show the above histogram. But consider, what if you need not find the number of pixels for all pixel values separately, but number of pixels in a interval of pixel values? say for example, you need to find the number of pixels lying between 0 to 15, then 16 to 31, ..., 240 to 255. You will need only 16 values to represent the histogram. And that is what is shown in example given in `OpenCV Tutorials on histograms `_. - -So what you do is simply split the whole histogram to 16 sub-parts and value of each sub-part is the sum of all pixel count in it. This each sub-part is called "BIN". In first case, number of bins where 256 (one for each pixel) while in second case, it is only 16. BINS is represented by the term **histSize** in OpenCV docs. - -**DIMS** : It is the number of parameters for which we collect the data. In this case, we collect data regarding only one thing, intensity value. So here it is 1. - -**RANGE** : It is the range of intensity values you want to measure. Normally, it is [0,256], ie all intensity values. - -1. Histogram Calculation in OpenCV --------------------------------------- - -So now we use **cv2.calcHist()** function to find the histogram. Let's familiarize with the function and its parameters : - -.. centered:: *cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])* - -#. images : it is the source image of type uint8 or float32. it should be given in square brackets, ie, "[img]". -#. channels : it is also given in square brackets. It is the index of channel for which we calculate histogram. For example, if input is grayscale image, its value is [0]. For color image, you can pass [0], [1] or [2] to calculate histogram of blue, green or red channel respectively. -#. mask : mask image. To find histogram of full image, it is given as "None". But if you want to find histogram of particular region of image, you have to create a mask image for that and give it as mask. (I will show an example later.) -#. histSize : this represents our BIN count. Need to be given in square brackets. For full scale, we pass [256]. -#. ranges : this is our RANGE. Normally, it is [0,256]. - -So let's start with a sample image. Simply load an image in grayscale mode and find its full histogram. - -:: - - img = cv2.imread('home.jpg',0) - hist = cv2.calcHist([img],[0],None,[256],[0,256]) - -hist is a 256x1 array, each value corresponds to number of pixels in that image with its corresponding pixel value. - -2. Histogram Calculation in Numpy ----------------------------------- -Numpy also provides you a function, **np.histogram()**. So instead of calcHist() function, you can try below line : -:: - - hist,bins = np.histogram(img.ravel(),256,[0,256]) - -hist is same as we calculated before. But bins will have 257 elements, because Numpy calculates bins as 0-0.99, 1-1.99, 2-2.99 etc. So final range would be 255-255.99. To represent that, they also add 256 at end of bins. But we don't need that 256. Upto 255 is sufficient. - -.. seealso:: Numpy has another function, **np.bincount()** which is much faster than (around 10X) np.histogram(). So for one-dimensional histograms, you can better try that. Don't forget to set ``minlength = 256`` in np.bincount. For example, ``hist = np.bincount(img.ravel(),minlength=256)`` - -.. note:: OpenCV function is more faster than (around 40X) than np.histogram(). So stick with OpenCV function. - -Now we should plot histograms, but how ? - -Plotting Histograms -====================== - -There are two ways for this, - #. Short Way : use Matplotlib plotting functions - #. Long Way : use OpenCV drawing functions - -1. Using Matplotlib ------------------------ -Matplotlib comes with a histogram plotting function : matplotlib.pyplot.hist() - -It directly finds the histogram and plot it. You need not use calcHist() or np.histogram() function to find the histogram. See the code below: -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('home.jpg',0) - plt.hist(img.ravel(),256,[0,256]); plt.show() - -You will get a plot as below : - - .. image:: images/histogram_matplotlib.jpg - :alt: Histogram Plotting in Matplotlib - :align: center - -Or you can use normal plot of matplotlib, which would be good for BGR plot. For that, you need to find the histogram data first. Try below code: -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('home.jpg') - color = ('b','g','r') - for i,col in enumerate(color): - histr = cv2.calcHist([img],[i],None,[256],[0,256]) - plt.plot(histr,color = col) - plt.xlim([0,256]) - plt.show() - -Result: - - .. image:: images/histogram_rgb_plot.jpg - :alt: Histogram Plotting in Matplotlib - :align: center - -You can deduct from the above graph that, blue has some high value areas in the image (obviously it should be due to the sky) - -2. Using OpenCV --------------------------- - -Well, here you adjust the values of histograms along with its bin values to look like x,y coordinates so that you can draw it using cv2.line() or cv2.polyline() function to generate same image as above. This is already available with OpenCV-Python2 official samples. `Check the Code `_ - -Application of Mask -===================== - -We used cv2.calcHist() to find the histogram of the full image. What if you want to find histograms of some regions of an image? Just create a mask image with white color on the region you want to find histogram and black otherwise. Then pass this as the mask. -:: - - img = cv2.imread('home.jpg',0) - - # create a mask - mask = np.zeros(img.shape[:2], np.uint8) - mask[100:300, 100:400] = 255 - masked_img = cv2.bitwise_and(img,img,mask = mask) - - # Calculate histogram with mask and without mask - # Check third argument for mask - hist_full = cv2.calcHist([img],[0],None,[256],[0,256]) - hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256]) - - plt.subplot(221), plt.imshow(img, 'gray') - plt.subplot(222), plt.imshow(mask,'gray') - plt.subplot(223), plt.imshow(masked_img, 'gray') - plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask) - plt.xlim([0,256]) - - plt.show() - -See the result. In the histogram plot, blue line shows histogram of full image while green line shows histogram of masked region. - - .. image:: images/histogram_masking.jpg - :alt: Histogram Example - :align: center - -Additional Resources -===================== -#. `Cambridge in Color website `_ - -Exercises -========== diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.rst b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.rst deleted file mode 100644 index cd446bd73f..0000000000 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.rst +++ /dev/null @@ -1,135 +0,0 @@ -.. _PY_Histogram_Equalization: - -Histograms - 2: Histogram Equalization -**************************************** - -Goal -====== - -In this section, - - * We will learn the concepts of histogram equalization and use it to improve the contrast of our images. - -Theory -========= - -Consider an image whose pixel values are confined to some specific range of values only. For eg, brighter image will have all pixels confined to high values. But a good image will have pixels from all regions of the image. So you need to stretch this histogram to either ends (as given in below image, from wikipedia) and that is what Histogram Equalization does (in simple words). This normally improves the contrast of the image. - - .. image:: images/histogram_equalization.png - :alt: Histograms Equalization - :align: center - -I would recommend you to read the wikipedia page on `Histogram Equalization `_ for more details about it. It has a very good explanation with worked out examples, so that you would understand almost everything after reading that. Instead, here we will see its Numpy implementation. After that, we will see OpenCV function. -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('wiki.jpg',0) - - hist,bins = np.histogram(img.flatten(),256,[0,256]) - - cdf = hist.cumsum() - cdf_normalized = cdf * hist.max()/ cdf.max() - - plt.plot(cdf_normalized, color = 'b') - plt.hist(img.flatten(),256,[0,256], color = 'r') - plt.xlim([0,256]) - plt.legend(('cdf','histogram'), loc = 'upper left') - plt.show() - -.. image:: images/histeq_numpy1.jpg - :alt: Histograms Equalization - :align: center - -You can see histogram lies in brighter region. We need the full spectrum. For that, we need a transformation function which maps the input pixels in brighter region to output pixels in full region. That is what histogram equalization does. - -Now we find the minimum histogram value (excluding 0) and apply the histogram equalization equation as given in wiki page. But I have used here, the masked array concept array from Numpy. For masked array, all operations are performed on non-masked elements. You can read more about it from Numpy docs on masked arrays. -:: - - cdf_m = np.ma.masked_equal(cdf,0) - cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min()) - cdf = np.ma.filled(cdf_m,0).astype('uint8') - -Now we have the look-up table that gives us the information on what is the output pixel value for every input pixel value. So we just apply the transform. -:: - - img2 = cdf[img] - -Now we calculate its histogram and cdf as before ( you do it) and result looks like below : - -.. image:: images/histeq_numpy2.jpg - :alt: Histograms Equalization - :align: center - -Another important feature is that, even if the image was a darker image (instead of a brighter one we used), after equalization we will get almost the same image as we got. As a result, this is used as a "reference tool" to make all images with same lighting conditions. This is useful in many cases. For example, in face recognition, before training the face data, the images of faces are histogram equalized to make them all with same lighting conditions. - -Histograms Equalization in OpenCV -=================================== - -OpenCV has a function to do this, **cv2.equalizeHist()**. Its input is just grayscale image and output is our histogram equalized image. - -Below is a simple code snippet showing its usage for same image we used : -:: - - img = cv2.imread('wiki.jpg',0) - equ = cv2.equalizeHist(img) - res = np.hstack((img,equ)) #stacking images side-by-side - cv2.imwrite('res.png',res) - -.. image:: images/equalization_opencv.jpg - :alt: Histograms Equalization - :align: center - -So now you can take different images with different light conditions, equalize it and check the results. - -Histogram equalization is good when histogram of the image is confined to a particular region. It won't work good in places where there is large intensity variations where histogram covers a large region, ie both bright and dark pixels are present. Please check the SOF links in Additional Resources. - - -CLAHE (Contrast Limited Adaptive Histogram Equalization) -============================================================ - -The first histogram equalization we just saw, considers the global contrast of the image. In many cases, it is not a good idea. For example, below image shows an input image and its result after global histogram equalization. - - .. image:: images/clahe_1.jpg - :alt: Problem of Global HE - :align: center - -It is true that the background contrast has improved after histogram equalization. But compare the face of statue in both images. We lost most of the information there due to over-brightness. It is because its histogram is not confined to a particular region as we saw in previous cases (Try to plot histogram of input image, you will get more intuition). - -So to solve this problem, **adaptive histogram equalization** is used. In this, image is divided into small blocks called "tiles" (tileSize is 8x8 by default in OpenCV). Then each of these blocks are histogram equalized as usual. So in a small area, histogram would confine to a small region (unless there is noise). If noise is there, it will be amplified. To avoid this, **contrast limiting** is applied. If any histogram bin is above the specified contrast limit (by default 40 in OpenCV), those pixels are clipped and distributed uniformly to other bins before applying histogram equalization. After equalization, to remove artifacts in tile borders, bilinear interpolation is applied. - -Below code snippet shows how to apply CLAHE in OpenCV: -:: - - import numpy as np - import cv2 - - img = cv2.imread('tsukuba_l.png',0) - - # create a CLAHE object (Arguments are optional). - clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) - cl1 = clahe.apply(img) - - cv2.imwrite('clahe_2.jpg',cl1) - -See the result below and compare it with results above, especially the statue region: - - .. image:: images/clahe_2.jpg - :alt: Result of CLAHE - :align: center - - -Additional Resources -====================== -1. Wikipedia page on `Histogram Equalization `_ -2. `Masked Arrays in Numpy `_ - -Also check these SOF questions regarding contrast adjustment: - -3. `How can I adjust contrast in OpenCV in C? `_ -4. `How do I equalize contrast & brightness of images using opencv? `_ - -Exercises -=========== diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/py_table_of_contents_histograms.markdown b/doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms.markdown similarity index 100% rename from doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/py_table_of_contents_histograms.markdown rename to doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms.markdown diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/py_table_of_contents_histograms.rst b/doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/py_table_of_contents_histograms.rst deleted file mode 100644 index 4c3cc50fd0..0000000000 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_table_of_contents_histograms/py_table_of_contents_histograms.rst +++ /dev/null @@ -1,77 +0,0 @@ -.. _Table-Of-Content-Histograms: - -Histograms in OpenCV ------------------------------------------------------------ - -* :ref:`Histograms_Getting_Started` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |hist_1| Learn to find and draw Contours - - - =========== =================================================================== - - .. |hist_1| image:: images/histograms_1d.jpg - :height: 90pt - :width: 90pt - -* :ref:`PY_Histogram_Equalization` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |hist_2| Learn to Equalize Histograms to get better contrast for images - - - =========== =================================================================== - - .. |hist_2| image:: images/histograms_equ.jpg - :height: 90pt - :width: 90pt - -* :ref:`TwoD_Histogram` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |hist_3| Learn to find and plot 2D Histograms - - - =========== =================================================================== - - .. |hist_3| image:: images/histograms_2d.jpg - :height: 90pt - :width: 90pt - -* :ref:`Histogram_Backprojection` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |hist_4| Learn histogram backprojection to segment colored objects - - - =========== =================================================================== - - .. |hist_4| image:: images/histograms_bp.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_histogram_begins/py_histogram_begins - ../py_histogram_equalization/py_histogram_equalization - ../py_2d_histogram/py_2d_histogram - ../py_histogram_backprojection/py_histogram_backprojection diff --git a/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.rst b/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.rst deleted file mode 100644 index f21ff1f1e7..0000000000 --- a/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. _Hough_Circles: - -Hough Circle Transform -************************** - -Goal -===== - -In this chapter, - * We will learn to use Hough Transform to find circles in an image. - * We will see these functions: **cv2.HoughCircles()** - -Theory -======== - -A circle is represented mathematically as :math:`(x-x_{center})^2 + (y - y_{center})^2 = r^2` where :math:`(x_{center},y_{center})` is the center of the circle, and :math:`r` is the radius of the circle. From equation, we can see we have 3 parameters, so we need a 3D accumulator for hough transform, which would be highly ineffective. So OpenCV uses more trickier method, **Hough Gradient Method** which uses the gradient information of edges. - -The function we use here is **cv2.HoughCircles()**. It has plenty of arguments which are well explained in the documentation. So we directly go to the code. -:: - - import cv2 - import numpy as np - - img = cv2.imread('opencv_logo.png',0) - img = cv2.medianBlur(img,5) - cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR) - - circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20, - param1=50,param2=30,minRadius=0,maxRadius=0) - - circles = np.uint16(np.around(circles)) - for i in circles[0,:]: - # draw the outer circle - cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2) - # draw the center of the circle - cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3) - - cv2.imshow('detected circles',cimg) - cv2.waitKey(0) - cv2.destroyAllWindows() - -Result is shown below: - - .. image:: images/houghcircles2.jpg - :alt: Hough Circles - :align: center - -Additional Resources -===================== - -Exercises -=========== diff --git a/doc/py_tutorials/py_imgproc/py_houghlines/py_houghlines.rst b/doc/py_tutorials/py_imgproc/py_houghlines/py_houghlines.rst deleted file mode 100644 index 5ff97d1f89..0000000000 --- a/doc/py_tutorials/py_imgproc/py_houghlines/py_houghlines.rst +++ /dev/null @@ -1,121 +0,0 @@ -.. _PY_Hough_Lines: - -Hough Line Transform -********************** - -Goal -===== - -In this chapter, - * We will understand the concept of Hough Tranform. - * We will see how to use it detect lines in an image. - * We will see following functions: **cv2.HoughLines()**, **cv2.HoughLinesP()** - -Theory -======== -Hough Transform is a popular technique to detect any shape, if you can represent that shape in mathematical form. It can detect the shape even if it is broken or distorted a little bit. We will see how it works for a line. - -A line can be represented as :math:`y = mx+c` or in parametric form, as :math:`\rho = x \cos \theta + y \sin \theta` where :math:`\rho` is the perpendicular distance from origin to the line, and :math:`\theta` is the angle formed by this perpendicular line and horizontal axis measured in counter-clockwise ( That direction varies on how you represent the coordinate system. This representation is used in OpenCV). Check below image: - - .. image:: images/houghlines1.svg - :alt: coordinate system - :align: center - :width: 200 pt - :height: 200 pt - -So if line is passing below the origin, it will have a positive rho and angle less than 180. If it is going above the origin, instead of taking angle greater than 180, angle is taken less than 180, and rho is taken negative. Any vertical line will have 0 degree and horizontal lines will have 90 degree. - -Now let's see how Hough Transform works for lines. Any line can be represented in these two terms, :math:`(\rho, \theta)`. So first it creates a 2D array or accumulator (to hold values of two parameters) and it is set to 0 initially. Let rows denote the :math:`\rho` and columns denote the :math:`\theta`. Size of array depends on the accuracy you need. Suppose you want the accuracy of angles to be 1 degree, you need 180 columns. For :math:`\rho`, the maximum distance possible is the diagonal length of the image. So taking one pixel accuracy, number of rows can be diagonal length of the image. - -Consider a 100x100 image with a horizontal line at the middle. Take the first point of the line. You know its (x,y) values. Now in the line equation, put the values :math:`\theta = 0,1,2,....,180` and check the :math:`\rho` you get. For every :math:`(\rho, \theta)` pair, you increment value by one in our accumulator in its corresponding :math:`(\rho, \theta)` cells. So now in accumulator, the cell (50,90) = 1 along with some other cells. - -Now take the second point on the line. Do the same as above. Increment the the values in the cells corresponding to :math:`(\rho, \theta)` you got. This time, the cell (50,90) = 2. What you actually do is voting the :math:`(\rho, \theta)` values. You continue this process for every point on the line. At each point, the cell (50,90) will be incremented or voted up, while other cells may or may not be voted up. This way, at the end, the cell (50,90) will have maximum votes. So if you search the accumulator for maximum votes, you get the value (50,90) which says, there is a line in this image at distance 50 from origin and at angle 90 degrees. It is well shown in below animation (Image Courtesy: `Amos Storkey `_ ) - - .. image:: images/houghlinesdemo.gif - :alt: Hough Transform Demo - :align: center - - -This is how hough transform for lines works. It is simple, and may be you can implement it using Numpy on your own. Below is an image which shows the accumulator. Bright spots at some locations denotes they are the parameters of possible lines in the image. (Image courtesy: `Wikipedia `_ ) - - .. image:: images/houghlines2.jpg - :alt: Hough Transform accumulator - :align: center - -Hough Tranform in OpenCV -========================= - -Everything explained above is encapsulated in the OpenCV function, **cv2.HoughLines()**. It simply returns an array of :math:`(\rho, \theta)` values. :math:`\rho` is measured in pixels and :math:`\theta` is measured in radians. First parameter, Input image should be a binary image, so apply threshold or use canny edge detection before finding applying hough transform. Second and third parameters are :math:`\rho` and :math:`\theta` accuracies respectively. Fourth argument is the `threshold`, which means minimum vote it should get for it to be considered as a line. Remember, number of votes depend upon number of points on the line. So it represents the minimum length of line that should be detected. -:: - - import cv2 - import numpy as np - - img = cv2.imread('dave.jpg') - gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - edges = cv2.Canny(gray,50,150,apertureSize = 3) - - lines = cv2.HoughLines(edges,1,np.pi/180,200) - for rho,theta in lines[0]: - a = np.cos(theta) - b = np.sin(theta) - x0 = a*rho - y0 = b*rho - x1 = int(x0 + 1000*(-b)) - y1 = int(y0 + 1000*(a)) - x2 = int(x0 - 1000*(-b)) - y2 = int(y0 - 1000*(a)) - - cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2) - - cv2.imwrite('houghlines3.jpg',img) - -Check the results below: - - .. image:: images/houghlines3.jpg - :alt: Hough Transform Line Detection - :align: center - -Probabilistic Hough Transform -============================== - -In the hough transform, you can see that even for a line with two arguments, it takes a lot of computation. Probabilistic Hough Transform is an optimization of Hough Transform we saw. It doesn't take all the points into consideration, instead take only a random subset of points and that is sufficient for line detection. Just we have to decrease the threshold. See below image which compare Hough Transform and Probabilistic Hough Transform in hough space. (Image Courtesy : `Franck Bettinger's home page `_ - - .. image:: images/houghlines4.png - :alt: Hough Transform and Probabilistic Hough Transform - :align: center - -OpenCV implementation is based on Robust Detection of Lines Using the Progressive Probabilistic Hough Transform by Matas, J. and Galambos, C. and Kittler, J.V.. The function used is **cv2.HoughLinesP()**. It has two new arguments. - * **minLineLength** - Minimum length of line. Line segments shorter than this are rejected. - * **maxLineGap** - Maximum allowed gap between line segments to treat them as single line. - -Best thing is that, it directly returns the two endpoints of lines. In previous case, you got only the parameters of lines, and you had to find all the points. Here, everything is direct and simple. -:: - - import cv2 - import numpy as np - - img = cv2.imread('dave.jpg') - gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - edges = cv2.Canny(gray,50,150,apertureSize = 3) - minLineLength = 100 - maxLineGap = 10 - lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap) - for x1,y1,x2,y2 in lines[0]: - cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2) - - cv2.imwrite('houghlines5.jpg',img) - -See the results below: - - .. image:: images/houghlines5.jpg - :alt: Probabilistic Hough Transform - :align: center - -Additional Resources -======================= -#. `Hough Transform on Wikipedia `_ - - -Exercises -=========== diff --git a/doc/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.rst b/doc/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.rst deleted file mode 100644 index ea85913ffa..0000000000 --- a/doc/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.rst +++ /dev/null @@ -1,161 +0,0 @@ -.. _Morphological_Ops: - -Morphological Transformations -******************************* - -Goal -====== - -In this chapter, - * We will learn different morphological operations like Erosion, Dilation, Opening, Closing etc. - * We will see different functions like : **cv2.erode()**, **cv2.dilate()**, **cv2.morphologyEx()** etc. - -Theory -======== - -Morphological transformations are some simple operations based on the image shape. It is normally performed on binary images. It needs two inputs, one is our original image, second one is called **structuring element** or **kernel** which decides the nature of operation. Two basic morphological operators are Erosion and Dilation. Then its variant forms like Opening, Closing, Gradient etc also comes into play. We will see them one-by-one with help of following image: - - .. image:: images/j.png - :alt: Input Image - :align: center - -1. Erosion --------------- -The basic idea of erosion is just like soil erosion only, it erodes away the boundaries of foreground object (Always try to keep foreground in white). So what it does? The kernel slides through the image (as in 2D convolution). A pixel in the original image (either 1 or 0) will be considered 1 only if all the pixels under the kernel is 1, otherwise it is eroded (made to zero). - -So what happends is that, all the pixels near boundary will be discarded depending upon the size of kernel. So the thickness or size of the foreground object decreases or simply white region decreases in the image. It is useful for removing small white noises (as we have seen in colorspace chapter), detach two connected objects etc. - -Here, as an example, I would use a 5x5 kernel with full of ones. Let's see it how it works: -:: - - import cv2 - import numpy as np - - img = cv2.imread('j.png',0) - kernel = np.ones((5,5),np.uint8) - erosion = cv2.erode(img,kernel,iterations = 1) - -Result: - - .. image:: images/erosion.png - :alt: Erosion - :align: center - -2. Dilation --------------- -It is just opposite of erosion. Here, a pixel element is '1' if atleast one pixel under the kernel is '1'. So it increases the white region in the image or size of foreground object increases. Normally, in cases like noise removal, erosion is followed by dilation. Because, erosion removes white noises, but it also shrinks our object. So we dilate it. Since noise is gone, they won't come back, but our object area increases. It is also useful in joining broken parts of an object. -:: - - dilation = cv2.dilate(img,kernel,iterations = 1) - -Result: - - .. image:: images/dilation.png - :alt: Dilation - :align: center - -3. Opening --------------- -Opening is just another name of **erosion followed by dilation**. It is useful in removing noise, as we explained above. Here we use the function, **cv2.morphologyEx()** -:: - - opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) - -Result: - - .. image:: images/opening.png - :alt: Opening - :align: center - -4. Closing --------------- -Closing is reverse of Opening, **Dilation followed by Erosion**. It is useful in closing small holes inside the foreground objects, or small black points on the object. -:: - - closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) - -Result: - - .. image:: images/closing.png - :alt: Closing - :align: center - -5. Morphological Gradient ------------------------------ -It is the difference between dilation and erosion of an image. - -The result will look like the outline of the object. -:: - - gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel) - -Result: - - .. image:: images/gradient.png - :alt: Gradient - :align: center - -6. Top Hat --------------- -It is the difference between input image and Opening of the image. Below example is done for a 9x9 kernel. -:: - - tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel) - -Result: - - .. image:: images/tophat.png - :alt: Top Hat - :align: center - -7. Black Hat --------------- -It is the difference between the closing of the input image and input image. -:: - - blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel) - -Result: - - .. image:: images/blackhat.png - :alt: Black Hat - :align: center - -Structuring Element -======================== - -We manually created a structuring elements in the previous examples with help of Numpy. It is rectangular shape. But in some cases, you may need elliptical/circular shaped kernels. So for this purpose, OpenCV has a function, **cv2.getStructuringElement()**. You just pass the shape and size of the kernel, you get the desired kernel. - -.. code-block:: python - - # Rectangular Kernel - >>> cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) - array([[1, 1, 1, 1, 1], - [1, 1, 1, 1, 1], - [1, 1, 1, 1, 1], - [1, 1, 1, 1, 1], - [1, 1, 1, 1, 1]], dtype=uint8) - - # Elliptical Kernel - >>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) - array([[0, 0, 1, 0, 0], - [1, 1, 1, 1, 1], - [1, 1, 1, 1, 1], - [1, 1, 1, 1, 1], - [0, 0, 1, 0, 0]], dtype=uint8) - - # Cross-shaped Kernel - >>> cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5)) - array([[0, 0, 1, 0, 0], - [0, 0, 1, 0, 0], - [1, 1, 1, 1, 1], - [0, 0, 1, 0, 0], - [0, 0, 1, 0, 0]], dtype=uint8) - -Additional Resources -======================= - -#. `Morphological Operations `_ at HIPR2 - -Exercises -========== diff --git a/doc/py_tutorials/py_imgproc/py_pyramids/py_pyramids.rst b/doc/py_tutorials/py_imgproc/py_pyramids/py_pyramids.rst deleted file mode 100644 index f5a0f015a7..0000000000 --- a/doc/py_tutorials/py_imgproc/py_pyramids/py_pyramids.rst +++ /dev/null @@ -1,128 +0,0 @@ -.. _PY_Pyramids: - -Image Pyramids -*************** - -Goal -====== -In this chapter, - * We will learn about Image Pyramids - * We will use Image pyramids to create a new fruit, "Orapple" - * We will see these functions: **cv2.pyrUp()**, **cv2.pyrDown()** - -Theory -========= - -Normally, we used to work with an image of constant size. But in some occassions, we need to work with images of different resolution of the same image. For example, while searching for something in an image, like face, we are not sure at what size the object will be present in the image. In that case, we will need to create a set of images with different resolution and search for object in all the images. These set of images with different resolution are called Image Pyramids (because when they are kept in a stack with biggest image at bottom and smallest image at top look like a pyramid). - -There are two kinds of Image Pyramids. 1) Gaussian Pyramid and 2) Laplacian Pyramids - -Higher level (Low resolution) in a Gaussian Pyramid is formed by removing consecutive rows and columns in Lower level (higher resolution) image. Then each pixel in higher level is formed by the contribution from 5 pixels in underlying level with gaussian weights. By doing so, a :math:`M \times N` image becomes :math:`M/2 \times N/2` image. So area reduces to one-fourth of original area. It is called an Octave. The same pattern continues as we go upper in pyramid (ie, resolution decreases). Similarly while expanding, area becomes 4 times in each level. We can find Gaussian pyramids using **cv2.pyrDown()** and **cv2.pyrUp()** functions. -:: - - img = cv2.imread('messi5.jpg') - lower_reso = cv2.pyrDown(higher_reso) - -Below is the 4 levels in an image pyramid. - - .. image:: images/messipyr.jpg - :alt: Gaussian Pyramid - :align: center - -Now you can go down the image pyramid with **cv2.pyrUp()** function. -:: - - higher_reso2 = cv2.pyrUp(lower_reso) - -Remember, `higher_reso2` is not equal to `higher_reso`, because once you decrease the resolution, you loose the information. Below image is 3 level down the pyramid created from smallest image in previous case. Compare it with original image: - - .. image:: images/messiup.jpg - :alt: Gaussian Pyramid - :align: center - -Laplacian Pyramids are formed from the Gaussian Pyramids. There is no exclusive function for that. Laplacian pyramid images are like edge images only. Most of its elements are zeros. They are used in image compression. A level in Laplacian Pyramid is formed by the difference between that level in Gaussian Pyramid and expanded version of its upper level in Gaussian Pyramid. The three levels of a Laplacian level will look like below (contrast is adjusted to enhance the contents): - - .. image:: images/lap.jpg - :alt: Laplacian Pyramid - :align: center - -Image Blending using Pyramids -============================== - -One application of Pyramids is Image Blending. For example, in image stitching, you will need to stack two images together, but it may not look good due to discontinuities between images. In that case, image blending with Pyramids gives you seamless blending without leaving much data in the images. One classical example of this is the blending of two fruits, Orange and Apple. See the result now itself to understand what I am saying: - - .. image:: images/orapple.jpg - :alt: Pyramid Blending - :align: center - -Please check first reference in additional resources, it has full diagramatic details on image blending, Laplacian Pyramids etc. Simply it is done as follows: - - #. Load the two images of apple and orange - #. Find the Gaussian Pyramids for apple and orange (in this particular example, number of levels is 6) - #. From Gaussian Pyramids, find their Laplacian Pyramids - #. Now join the left half of apple and right half of orange in each levels of Laplacian Pyramids - #. Finally from this joint image pyramids, reconstruct the original image. - -Below is the full code. (For sake of simplicity, each step is done separately which may take more memory. You can optimize it if you want so). -:: - - import cv2 - import numpy as np,sys - - A = cv2.imread('apple.jpg') - B = cv2.imread('orange.jpg') - - # generate Gaussian pyramid for A - G = A.copy() - gpA = [G] - for i in xrange(6): - G = cv2.pyrDown(G) - gpA.append(G) - - # generate Gaussian pyramid for B - G = B.copy() - gpB = [G] - for i in xrange(6): - G = cv2.pyrDown(G) - gpB.append(G) - - # generate Laplacian Pyramid for A - lpA = [gpA[5]] - for i in xrange(5,0,-1): - GE = cv2.pyrUp(gpA[i]) - L = cv2.subtract(gpA[i-1],GE) - lpA.append(L) - - # generate Laplacian Pyramid for B - lpB = [gpB[5]] - for i in xrange(5,0,-1): - GE = cv2.pyrUp(gpB[i]) - L = cv2.subtract(gpB[i-1],GE) - lpB.append(L) - - # Now add left and right halves of images in each level - LS = [] - for la,lb in zip(lpA,lpB): - rows,cols,dpt = la.shape - ls = np.hstack((la[:,0:cols/2], lb[:,cols/2:])) - LS.append(ls) - - # now reconstruct - ls_ = LS[0] - for i in xrange(1,6): - ls_ = cv2.pyrUp(ls_) - ls_ = cv2.add(ls_, LS[i]) - - # image with direct connecting each half - real = np.hstack((A[:,:cols/2],B[:,cols/2:])) - - cv2.imwrite('Pyramid_blending2.jpg',ls_) - cv2.imwrite('Direct_blending.jpg',real) - -Additional Resources -========================= - -#. `Image Blending `_ - -Exercises -========== diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/py_table_of_contents_imgproc.markdown b/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc.markdown similarity index 100% rename from doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/py_table_of_contents_imgproc.markdown rename to doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc.markdown diff --git a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/py_table_of_contents_imgproc.rst b/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/py_table_of_contents_imgproc.rst deleted file mode 100644 index 90a1ad9af5..0000000000 --- a/doc/py_tutorials/py_imgproc/py_table_of_contents_imgproc/py_table_of_contents_imgproc.rst +++ /dev/null @@ -1,256 +0,0 @@ -.. _PY_Table-Of-Content-ImgProc: - -Image Processing in OpenCV ------------------------------------------------------------ - -* :ref:`Converting_colorspaces` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |imgproc_1| Learn to change images between different color spaces. - - Plus learn to track a colored object in a video. - =========== =================================================================== - - .. |imgproc_1| image:: images/colorspace.jpg - :height: 90pt - :width: 90pt - -* :ref:`Geometric_Transformations` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ =================================================================== - |imgproc_gt| Learn to apply different geometric transformations to images like rotation, translation etc. - - ============ =================================================================== - - .. |imgproc_gt| image:: images/geometric.jpg - :height: 90pt - :width: 90pt - -* :ref:`Thresholding` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |imgproc_2| Learn to convert images to binary images using global thresholding, - Adaptive thresholding, Otsu's binarization etc - - =========== =================================================================== - - .. |imgproc_2| image:: images/thresh.jpg - :height: 90pt - :width: 90pt - -* :ref:`Filtering` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |imgproc_4| Learn to blur the images, filter the images with custom kernels etc. - - =========== =================================================================== - - .. |imgproc_4| image:: images/blurring.jpg - :height: 90pt - :width: 90pt - -* :ref:`Morphological_Ops` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ =================================================================== - |imgproc_12| Learn about morphological transformations like Erosion, Dilation, Opening, Closing etc - - ============ =================================================================== - - .. |imgproc_12| image:: images/morphology.jpg - :height: 90pt - :width: 90pt - -* :ref:`Gradients` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |imgproc_5| Learn to find image gradients, edges etc. - - =========== =================================================================== - - .. |imgproc_5| image:: images/gradient.jpg - :height: 90pt - :width: 90pt - -* :ref:`Canny` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |imgproc_8| Learn to find edges with Canny Edge Detection - - =========== =================================================================== - - .. |imgproc_8| image:: images/canny.jpg - :height: 90pt - :width: 90pt - -* :ref:`PY_Pyramids` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ =================================================================== - |imgproc_14| Learn about image pyramids and how to use them for image blending - - ============ =================================================================== - - .. |imgproc_14| image:: images/pyramid.png - :height: 90pt - :width: 90pt - -* :ref:`Table-Of-Content-Contours` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |imgproc_3| All about Contours in OpenCV - - =========== =================================================================== - - .. |imgproc_3| image:: images/contours.jpg - :height: 90pt - :width: 90pt - -* :ref:`Table-Of-Content-Histograms` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |imgproc_6| All about histograms in OpenCV - - =========== =================================================================== - - .. |imgproc_6| image:: images/histogram.jpg - :height: 90pt - :width: 90pt - -* :ref:`Table-Of-Content-Transforms` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |imgproc_7| Meet different Image Transforms in OpenCV like Fourier Transform, Cosine Transform etc. - - =========== =================================================================== - - .. |imgproc_7| image:: images/transforms.jpg - :height: 90pt - :width: 90pt - -* :ref:`PY_Template_Matching` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |imgproc_9| Learn to search for an object in an image using Template Matching - - =========== =================================================================== - - .. |imgproc_9| image:: images/template.jpg - :height: 90pt - :width: 90pt - -* :ref:`PY_Hough_Lines` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ =================================================================== - |imgproc_10| Learn to detect lines in an image - - ============ =================================================================== - - .. |imgproc_10| image:: images/houghlines.jpg - :height: 90pt - :width: 90pt - -* :ref:`Hough_Circles` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ =================================================================== - |imgproc_11| Learn to detect circles in an image - - ============ =================================================================== - - .. |imgproc_11| image:: images/houghcircles.jpg - :height: 90pt - :width: 90pt - -* :ref:`Watershed` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ =================================================================== - |imgproc_13| Learn to segment images with watershed segmentation - - ============ =================================================================== - - .. |imgproc_13| image:: images/watershed.jpg - :height: 90pt - :width: 90pt - -* :ref:`grabcut` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ =================================================================== - |imgproc_15| Learn to extract foreground with GrabCut algorithm - - ============ =================================================================== - - .. |imgproc_15| image:: images/grabcut.jpg - :height: 90pt - :width: 90pt - - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_colorspaces/py_colorspaces - ../py_thresholding/py_thresholding - ../py_geometric_transformations/py_geometric_transformations - ../py_filtering/py_filtering - ../py_morphological_ops/py_morphological_ops - ../py_gradients/py_gradients - ../py_canny/py_canny - ../py_pyramids/py_pyramids - ../py_contours/py_table_of_contents_contours/py_table_of_contents_contours - ../py_histograms/py_table_of_contents_histograms/py_table_of_contents_histograms - ../py_transforms/py_table_of_contents_transforms/py_table_of_contents_transforms - ../py_template_matching/py_template_matching - ../py_houghlines/py_houghlines - ../py_houghcircles/py_houghcircles - ../py_watershed/py_watershed - ../py_grabcut/py_grabcut diff --git a/doc/py_tutorials/py_imgproc/py_template_matching/py_template_matching.rst b/doc/py_tutorials/py_imgproc/py_template_matching/py_template_matching.rst deleted file mode 100644 index 089cfe8a95..0000000000 --- a/doc/py_tutorials/py_imgproc/py_template_matching/py_template_matching.rst +++ /dev/null @@ -1,145 +0,0 @@ -.. _PY_Template_Matching: - -Template Matching -********************** - -Goals -========= - -In this chapter, you will learn - * To find objects in an image using Template Matching - * You will see these functions : **cv2.matchTemplate()**, **cv2.minMaxLoc()** - -Theory -======== - -Template Matching is a method for searching and finding the location of a template image in a larger image. OpenCV comes with a function **cv2.matchTemplate()** for this purpose. It simply slides the template image over the input image (as in 2D convolution) and compares the template and patch of input image under the template image. Several comparison methods are implemented in OpenCV. (You can check docs for more details). It returns a grayscale image, where each pixel denotes how much does the neighbourhood of that pixel match with template. - -If input image is of size `(WxH)` and template image is of size `(wxh)`, output image will have a size of `(W-w+1, H-h+1)`. Once you got the result, you can use **cv2.minMaxLoc()** function to find where is the maximum/minimum value. Take it as the top-left corner of rectangle and take `(w,h)` as width and height of the rectangle. That rectangle is your region of template. - -.. note:: If you are using ``cv2.TM_SQDIFF`` as comparison method, minimum value gives the best match. - -Template Matching in OpenCV -============================ - -Here, as an example, we will search for Messi's face in his photo. So I created a template as below: - - .. image:: images/messi_face.jpg - :alt: Template Image - :align: center - -We will try all the comparison methods so that we can see how their results look like: -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('messi5.jpg',0) - img2 = img.copy() - template = cv2.imread('template.jpg',0) - w, h = template.shape[::-1] - - # All the 6 methods for comparison in a list - methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR', - 'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED'] - - for meth in methods: - img = img2.copy() - method = eval(meth) - - # Apply template Matching - res = cv2.matchTemplate(img,template,method) - min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) - - # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum - if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]: - top_left = min_loc - else: - top_left = max_loc - bottom_right = (top_left[0] + w, top_left[1] + h) - - cv2.rectangle(img,top_left, bottom_right, 255, 2) - - plt.subplot(121),plt.imshow(res,cmap = 'gray') - plt.title('Matching Result'), plt.xticks([]), plt.yticks([]) - plt.subplot(122),plt.imshow(img,cmap = 'gray') - plt.title('Detected Point'), plt.xticks([]), plt.yticks([]) - plt.suptitle(meth) - - plt.show() - -See the results below: - - * cv2.TM_CCOEFF - - .. image:: images/template_ccoeff_1.jpg - :alt: Template Image - :align: center - - * cv2.TM_CCOEFF_NORMED - - .. image:: images/template_ccoeffn_2.jpg - :alt: Template Image - :align: center - - * cv2.TM_CCORR - - .. image:: images/template_ccorr_3.jpg - :alt: Template Image - :align: center - - * cv2.TM_CCORR_NORMED - - .. image:: images/template_ccorrn_4.jpg - :alt: Template Image - :align: center - - * cv2.TM_SQDIFF - - .. image:: images/template_sqdiff_5.jpg - :alt: Template Image - :align: center - - * cv2.TM_SQDIFF_NORMED - - .. image:: images/template_sqdiffn_6.jpg - :alt: Template Image - :align: center - -You can see that the result using **cv2.TM_CCORR** is not good as we expected. - -Template Matching with Multiple Objects -========================================== - -In the previous section, we searched image for Messi's face, which occurs only once in the image. Suppose you are searching for an object which has multiple occurances, **cv2.minMaxLoc()** won't give you all the locations. In that case, we will use thresholding. So in this example, we will use a screenshot of the famous game **Mario** and we will find the coins in it. -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img_rgb = cv2.imread('mario.png') - img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY) - template = cv2.imread('mario_coin.png',0) - w, h = template.shape[::-1] - - res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED) - threshold = 0.8 - loc = np.where( res >= threshold) - for pt in zip(*loc[::-1]): - cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2) - - cv2.imwrite('res.png',img_rgb) - -Result: - - .. image:: images/res_mario.jpg - :alt: Template Matching - :align: center - -Additional Resources -===================== - -Exercises -============ diff --git a/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.rst b/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.rst deleted file mode 100644 index 134e6c12c2..0000000000 --- a/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.rst +++ /dev/null @@ -1,221 +0,0 @@ -.. _Thresholding: - -Image Thresholding -******************** - -Goal -====== - -.. container:: enumeratevisibleitemswithsquare - - * In this tutorial, you will learn Simple thresholding, Adaptive thresholding, Otsu's thresholding etc. - * You will learn these functions : **cv2.threshold**, **cv2.adaptiveThreshold** etc. - -Simple Thresholding -===================== - -Here, the matter is straight forward. If pixel value is greater than a threshold value, it is assigned one value (may be white), else it is assigned another value (may be black). The function used is **cv2.threshold**. First argument is the source image, which **should be a grayscale image**. Second argument is the threshold value which is used to classify the pixel values. Third argument is the maxVal which represents the value to be given if pixel value is more than (sometimes less than) the threshold value. OpenCV provides different styles of thresholding and it is decided by the fourth parameter of the function. Different types are: - - * cv2.THRESH_BINARY - * cv2.THRESH_BINARY_INV - * cv2.THRESH_TRUNC - * cv2.THRESH_TOZERO - * cv2.THRESH_TOZERO_INV - -Documentation clearly explain what each type is meant for. Please check out the documentation. - -Two outputs are obtained. First one is a **retval** which will be explained later. Second output is our **thresholded image**. - -Code : -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('gradient.png',0) - ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY) - ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV) - ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC) - ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO) - ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV) - - titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV'] - images = [img, thresh1, thresh2, thresh3, thresh4, thresh5] - - for i in xrange(6): - plt.subplot(2,3,i+1),plt.imshow(images[i],'gray') - plt.title(titles[i]) - plt.xticks([]),plt.yticks([]) - - plt.show() - -.. note:: To plot multiple images, we have used `plt.subplot()` function. Please checkout Matplotlib docs for more details. - -Result is given below : - - .. image:: images/threshold.jpg - :alt: Simple Thresholding - :align: center - -Adaptive Thresholding -======================== - -In the previous section, we used a global value as threshold value. But it may not be good in all the conditions where image has different lighting conditions in different areas. In that case, we go for adaptive thresholding. In this, the algorithm calculate the threshold for a small regions of the image. So we get different thresholds for different regions of the same image and it gives us better results for images with varying illumination. - -It has three ‘special’ input params and only one output argument. - -**Adaptive Method** - It decides how thresholding value is calculated. - * cv2.ADAPTIVE_THRESH_MEAN_C : threshold value is the mean of neighbourhood area. - * cv2.ADAPTIVE_THRESH_GAUSSIAN_C : threshold value is the weighted sum of neighbourhood values where weights are a gaussian window. - -**Block Size** - It decides the size of neighbourhood area. - -**C** - It is just a constant which is subtracted from the mean or weighted mean calculated. - -Below piece of code compares global thresholding and adaptive thresholding for an image with varying illumination: -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('dave.jpg',0) - img = cv2.medianBlur(img,5) - - ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY) - th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\ - cv2.THRESH_BINARY,11,2) - th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\ - cv2.THRESH_BINARY,11,2) - - titles = ['Original Image', 'Global Thresholding (v = 127)', - 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding'] - images = [img, th1, th2, th3] - - for i in xrange(4): - plt.subplot(2,2,i+1),plt.imshow(images[i],'gray') - plt.title(titles[i]) - plt.xticks([]),plt.yticks([]) - plt.show() - -Result : - - .. image:: images/ada_threshold.jpg - :alt: Adaptive Thresholding - :align: center - -Otsu’s Binarization -===================== - -In the first section, I told you there is a second parameter **retVal**. Its use comes when we go for Otsu’s Binarization. So what is it? - -In global thresholding, we used an arbitrary value for threshold value, right? So, how can we know a value we selected is good or not? Answer is, trial and error method. But consider a **bimodal image** (*In simple words, bimodal image is an image whose histogram has two peaks*). For that image, we can approximately take a value in the middle of those peaks as threshold value, right ? That is what Otsu binarization does. So in simple words, it automatically calculates a threshold value from image histogram for a bimodal image. (For images which are not bimodal, binarization won’t be accurate.) - -For this, our cv2.threshold() function is used, but pass an extra flag, `cv2.THRESH_OTSU`. **For threshold value, simply pass zero**. Then the algorithm finds the optimal threshold value and returns you as the second output, ``retVal``. If Otsu thresholding is not used, retVal is same as the threshold value you used. - -Check out below example. Input image is a noisy image. In first case, I applied global thresholding for a value of 127. In second case, I applied Otsu’s thresholding directly. In third case, I filtered image with a 5x5 gaussian kernel to remove the noise, then applied Otsu thresholding. See how noise filtering improves the result. -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('noisy2.png',0) - - # global thresholding - ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY) - - # Otsu's thresholding - ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) - - # Otsu's thresholding after Gaussian filtering - blur = cv2.GaussianBlur(img,(5,5),0) - ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) - - # plot all the images and their histograms - images = [img, 0, th1, - img, 0, th2, - blur, 0, th3] - titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)', - 'Original Noisy Image','Histogram',"Otsu's Thresholding", - 'Gaussian filtered Image','Histogram',"Otsu's Thresholding"] - - for i in xrange(3): - plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray') - plt.title(titles[i*3]), plt.xticks([]), plt.yticks([]) - plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256) - plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([]) - plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray') - plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([]) - plt.show() - -Result : - - .. image:: images/otsu.jpg - :alt: Otsu's Thresholding - :align: center - -How Otsu's Binarization Works? ----------------------------------- - -This section demonstrates a Python implementation of Otsu's binarization to show how it works actually. If you are not interested, you can skip this. - -Since we are working with bimodal images, Otsu's algorithm tries to find a threshold value (t) which minimizes the **weighted within-class variance** given by the relation : - -.. math:: - \sigma_w^2(t) = q_1(t)\sigma_1^2(t)+q_2(t)\sigma_2^2(t) - -where - -.. math:: - q_1(t) = \sum_{i=1}^{t} P(i) \quad \& \quad q_1(t) = \sum_{i=t+1}^{I} P(i) - - \mu_1(t) = \sum_{i=1}^{t} \frac{iP(i)}{q_1(t)} \quad \& \quad \mu_2(t) = \sum_{i=t+1}^{I} \frac{iP(i)}{q_2(t)} - - \sigma_1^2(t) = \sum_{i=1}^{t} [i-\mu_1(t)]^2 \frac{P(i)}{q_1(t)} \quad \& \quad \sigma_2^2(t) = \sum_{i=t+1}^{I} [i-\mu_1(t)]^2 \frac{P(i)}{q_2(t)} - -It actually finds a value of t which lies in between two peaks such that variances to both classes are minimum. It can be simply implemented in Python as follows: -:: - - img = cv2.imread('noisy2.png',0) - blur = cv2.GaussianBlur(img,(5,5),0) - - # find normalized_histogram, and its cumulative distribution function - hist = cv2.calcHist([blur],[0],None,[256],[0,256]) - hist_norm = hist.ravel()/hist.max() - Q = hist_norm.cumsum() - - bins = np.arange(256) - - fn_min = np.inf - thresh = -1 - - for i in xrange(1,256): - p1,p2 = np.hsplit(hist_norm,[i]) # probabilities - q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes - b1,b2 = np.hsplit(bins,[i]) # weights - - # finding means and variances - m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2 - v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2 - - # calculates the minimization function - fn = v1*q1 + v2*q2 - if fn < fn_min: - fn_min = fn - thresh = i - - # find otsu's threshold value with OpenCV function - ret, otsu = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) - print thresh,ret - -*(Some of the functions may be new here, but we will cover them in coming chapters)* - -Additional Resources -===================== -#. Digital Image Processing, Rafael C. Gonzalez - -Exercises -=========== -#. There are some optimizations available for Otsu's binarization. You can search and implement it. diff --git a/doc/py_tutorials/py_imgproc/py_transforms/py_table_of_contents_transforms/images/transform_fourier.jpg b/doc/py_tutorials/py_imgproc/py_transforms/images/transform_fourier.jpg similarity index 100% rename from doc/py_tutorials/py_imgproc/py_transforms/py_table_of_contents_transforms/images/transform_fourier.jpg rename to doc/py_tutorials/py_imgproc/py_transforms/images/transform_fourier.jpg diff --git a/doc/py_tutorials/py_imgproc/py_transforms/py_fourier_transform/py_fourier_transform.rst b/doc/py_tutorials/py_imgproc/py_transforms/py_fourier_transform/py_fourier_transform.rst deleted file mode 100644 index 532ae80e09..0000000000 --- a/doc/py_tutorials/py_imgproc/py_transforms/py_fourier_transform/py_fourier_transform.rst +++ /dev/null @@ -1,255 +0,0 @@ -.. _Fourier_Transform: - -Fourier Transform -******************* - -Goal -====== - -In this section, we will learn - * To find the Fourier Transform of images using OpenCV - * To utilize the FFT functions available in Numpy - * Some applications of Fourier Transform - * We will see following functions : **cv2.dft()**, **cv2.idft()** etc - -Theory -======== - -Fourier Transform is used to analyze the frequency characteristics of various filters. For images, **2D Discrete Fourier Transform (DFT)** is used to find the frequency domain. A fast algorithm called **Fast Fourier Transform (FFT)** is used for calculation of DFT. Details about these can be found in any image processing or signal processing textbooks. Please see `Additional Resources`_ section. - -For a sinusoidal signal, :math:`x(t) = A \sin(2 \pi ft)`, we can say :math:`f` is the frequency of signal, and if its frequency domain is taken, we can see a spike at :math:`f`. If signal is sampled to form a discrete signal, we get the same frequency domain, but is periodic in the range :math:`[- \pi, \pi]` or :math:`[0,2\pi]` (or :math:`[0,N]` for N-point DFT). You can consider an image as a signal which is sampled in two directions. So taking fourier transform in both X and Y directions gives you the frequency representation of image. - -More intuitively, for the sinusoidal signal, if the amplitude varies so fast in short time, you can say it is a high frequency signal. If it varies slowly, it is a low frequency signal. You can extend the same idea to images. Where does the amplitude varies drastically in images ? At the edge points, or noises. So we can say, edges and noises are high frequency contents in an image. If there is no much changes in amplitude, it is a low frequency component. ( Some links are added to `Additional Resources`_ which explains frequency transform intuitively with examples). - -Now we will see how to find the Fourier Transform. - -Fourier Transform in Numpy -============================ -First we will see how to find Fourier Transform using Numpy. Numpy has an FFT package to do this. **np.fft.fft2()** provides us the frequency transform which will be a complex array. Its first argument is the input image, which is grayscale. Second argument is optional which decides the size of output array. If it is greater than size of input image, input image is padded with zeros before calculation of FFT. If it is less than input image, input image will be cropped. If no arguments passed, Output array size will be same as input. - -Now once you got the result, zero frequency component (DC component) will be at top left corner. If you want to bring it to center, you need to shift the result by :math:`\frac{N}{2}` in both the directions. This is simply done by the function, **np.fft.fftshift()**. (It is more easier to analyze). Once you found the frequency transform, you can find the magnitude spectrum. -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - img = cv2.imread('messi5.jpg',0) - f = np.fft.fft2(img) - fshift = np.fft.fftshift(f) - magnitude_spectrum = 20*np.log(np.abs(fshift)) - - plt.subplot(121),plt.imshow(img, cmap = 'gray') - plt.title('Input Image'), plt.xticks([]), plt.yticks([]) - plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray') - plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([]) - plt.show() - -Result look like below: - - .. image:: images/fft1.jpg - :alt: Magnitude Spectrum - :align: center - -See, You can see more whiter region at the center showing low frequency content is more. - -So you found the frequency transform Now you can do some operations in frequency domain, like high pass filtering and reconstruct the image, ie find inverse DFT. For that you simply remove the low frequencies by masking with a rectangular window of size 60x60. Then apply the inverse shift using **np.fft.ifftshift()** so that DC component again come at the top-left corner. Then find inverse FFT using **np.ifft2()** function. The result, again, will be a complex number. You can take its absolute value. -:: - - rows, cols = img.shape - crow,ccol = rows/2 , cols/2 - fshift[crow-30:crow+30, ccol-30:ccol+30] = 0 - f_ishift = np.fft.ifftshift(fshift) - img_back = np.fft.ifft2(f_ishift) - img_back = np.abs(img_back) - - plt.subplot(131),plt.imshow(img, cmap = 'gray') - plt.title('Input Image'), plt.xticks([]), plt.yticks([]) - plt.subplot(132),plt.imshow(img_back, cmap = 'gray') - plt.title('Image after HPF'), plt.xticks([]), plt.yticks([]) - plt.subplot(133),plt.imshow(img_back) - plt.title('Result in JET'), plt.xticks([]), plt.yticks([]) - - plt.show() - -Result look like below: - - .. image:: images/fft2.jpg - :alt: High Pass Filtering - :align: center - -The result shows High Pass Filtering is an edge detection operation. This is what we have seen in Image Gradients chapter. This also shows that most of the image data is present in the Low frequency region of the spectrum. Anyway we have seen how to find DFT, IDFT etc in Numpy. Now let's see how to do it in OpenCV. - -If you closely watch the result, especially the last image in JET color, you can see some artifacts (One instance I have marked in red arrow). It shows some ripple like structures there, and it is called **ringing effects**. It is caused by the rectangular window we used for masking. This mask is converted to sinc shape which causes this problem. So rectangular windows is not used for filtering. Better option is Gaussian Windows. - -Fourier Transform in OpenCV -============================ - -OpenCV provides the functions **cv2.dft()** and **cv2.idft()** for this. It returns the same result as previous, but with two channels. First channel will have the real part of the result and second channel will have the imaginary part of the result. The input image should be converted to np.float32 first. We will see how to do it. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img = cv2.imread('messi5.jpg',0) - - dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT) - dft_shift = np.fft.fftshift(dft) - - magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1])) - - plt.subplot(121),plt.imshow(img, cmap = 'gray') - plt.title('Input Image'), plt.xticks([]), plt.yticks([]) - plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray') - plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([]) - plt.show() - -.. note:: You can also use **cv2.cartToPolar()** which returns both magnitude and phase in a single shot - -So, now we have to do inverse DFT. In previous session, we created a HPF, this time we will see how to remove high frequency contents in the image, ie we apply LPF to image. It actually blurs the image. For this, we create a mask first with high value (1) at low frequencies, ie we pass the LF content, and 0 at HF region. -:: - - rows, cols = img.shape - crow,ccol = rows/2 , cols/2 - - # create a mask first, center square is 1, remaining all zeros - mask = np.zeros((rows,cols,2),np.uint8) - mask[crow-30:crow+30, ccol-30:ccol+30] = 1 - - # apply mask and inverse DFT - fshift = dft_shift*mask - f_ishift = np.fft.ifftshift(fshift) - img_back = cv2.idft(f_ishift) - img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1]) - - plt.subplot(121),plt.imshow(img, cmap = 'gray') - plt.title('Input Image'), plt.xticks([]), plt.yticks([]) - plt.subplot(122),plt.imshow(img_back, cmap = 'gray') - plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([]) - plt.show() - -See the result: - - .. image:: images/fft4.jpg - :alt: Magnitude Spectrum - :align: center - -.. note:: As usual, OpenCV functions **cv2.dft()** and **cv2.idft()** are faster than Numpy counterparts. But Numpy functions are more user-friendly. For more details about performance issues, see below section. - -Performance Optimization of DFT -================================== - -Performance of DFT calculation is better for some array size. It is fastest when array size is power of two. The arrays whose size is a product of 2’s, 3’s, and 5’s are also processed quite efficiently. So if you are worried about the performance of your code, you can modify the size of the array to any optimal size (by padding zeros) before finding DFT. For OpenCV, you have to manually pad zeros. But for Numpy, you specify the new size of FFT calculation, and it will automatically pad zeros for you. - -So how do we find this optimal size ? OpenCV provides a function, **cv2.getOptimalDFTSize()** for this. It is applicable to both **cv2.dft()** and **np.fft.fft2()**. Let's check their performance using IPython magic command ``%timeit``. -:: - - In [16]: img = cv2.imread('messi5.jpg',0) - In [17]: rows,cols = img.shape - In [18]: print rows,cols - 342 548 - - In [19]: nrows = cv2.getOptimalDFTSize(rows) - In [20]: ncols = cv2.getOptimalDFTSize(cols) - In [21]: print nrows, ncols - 360 576 - -See, the size (342,548) is modified to (360, 576). Now let's pad it with zeros (for OpenCV) and find their DFT calculation performance. You can do it by creating a new big zero array and copy the data to it, or use **cv2.copyMakeBorder()**. -:: - - nimg = np.zeros((nrows,ncols)) - nimg[:rows,:cols] = img - -OR: -:: - - right = ncols - cols - bottom = nrows - rows - bordertype = cv2.BORDER_CONSTANT #just to avoid line breakup in PDF file - nimg = cv2.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0) - -Now we calculate the DFT performance comparison of Numpy function: -:: - - In [22]: %timeit fft1 = np.fft.fft2(img) - 10 loops, best of 3: 40.9 ms per loop - In [23]: %timeit fft2 = np.fft.fft2(img,[nrows,ncols]) - 100 loops, best of 3: 10.4 ms per loop - -It shows a 4x speedup. Now we will try the same with OpenCV functions. -:: - - In [24]: %timeit dft1= cv2.dft(np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT) - 100 loops, best of 3: 13.5 ms per loop - In [27]: %timeit dft2= cv2.dft(np.float32(nimg),flags=cv2.DFT_COMPLEX_OUTPUT) - 100 loops, best of 3: 3.11 ms per loop - -It also shows a 4x speed-up. You can also see that OpenCV functions are around 3x faster than Numpy functions. This can be tested for inverse FFT also, and that is left as an exercise for you. - -Why Laplacian is a High Pass Filter? -======================================= - -A similar question was asked in a forum. The question is, why Laplacian is a high pass filter? Why Sobel is a HPF? etc. And the first answer given to it was in terms of Fourier Transform. Just take the fourier transform of Laplacian for some higher size of FFT. Analyze it: -:: - - import cv2 - import numpy as np - from matplotlib import pyplot as plt - - # simple averaging filter without scaling parameter - mean_filter = np.ones((3,3)) - - # creating a guassian filter - x = cv2.getGaussianKernel(5,10) - gaussian = x*x.T - - # different edge detecting filters - # scharr in x-direction - scharr = np.array([[-3, 0, 3], - [-10,0,10], - [-3, 0, 3]]) - # sobel in x direction - sobel_x= np.array([[-1, 0, 1], - [-2, 0, 2], - [-1, 0, 1]]) - # sobel in y direction - sobel_y= np.array([[-1,-2,-1], - [0, 0, 0], - [1, 2, 1]]) - # laplacian - laplacian=np.array([[0, 1, 0], - [1,-4, 1], - [0, 1, 0]]) - - filters = [mean_filter, gaussian, laplacian, sobel_x, sobel_y, scharr] - filter_name = ['mean_filter', 'gaussian','laplacian', 'sobel_x', \ - 'sobel_y', 'scharr_x'] - fft_filters = [np.fft.fft2(x) for x in filters] - fft_shift = [np.fft.fftshift(y) for y in fft_filters] - mag_spectrum = [np.log(np.abs(z)+1) for z in fft_shift] - - for i in xrange(6): - plt.subplot(2,3,i+1),plt.imshow(mag_spectrum[i],cmap = 'gray') - plt.title(filter_name[i]), plt.xticks([]), plt.yticks([]) - - plt.show() - -See the result: - - .. image:: images/fft5.jpg - :alt: Frequency Spectrum of different Kernels - :align: center - -From image, you can see what frequency region each kernel blocks, and what region it passes. From that information, we can say why each kernel is a HPF or a LPF - -Additional Resources -===================== - -1. `An Intuitive Explanation of Fourier Theory `_ by Steven Lehar -2. `Fourier Transform `_ at HIPR -3. `What does frequency domain denote in case of images? `_ - - -Exercises -============ diff --git a/doc/py_tutorials/py_imgproc/py_transforms/py_table_of_contents_transforms/py_table_of_contents_transforms.markdown b/doc/py_tutorials/py_imgproc/py_transforms/py_table_of_contents_transforms.markdown similarity index 100% rename from doc/py_tutorials/py_imgproc/py_transforms/py_table_of_contents_transforms/py_table_of_contents_transforms.markdown rename to doc/py_tutorials/py_imgproc/py_transforms/py_table_of_contents_transforms.markdown diff --git a/doc/py_tutorials/py_imgproc/py_transforms/py_table_of_contents_transforms/py_table_of_contents_transforms.rst b/doc/py_tutorials/py_imgproc/py_transforms/py_table_of_contents_transforms/py_table_of_contents_transforms.rst deleted file mode 100644 index 7aa17e8e3a..0000000000 --- a/doc/py_tutorials/py_imgproc/py_transforms/py_table_of_contents_transforms/py_table_of_contents_transforms.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _Table-Of-Content-Transforms: - -Image Transforms in OpenCV ------------------------------------------------------------ - -* :ref:`Fourier_Transform` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============= =================================================================== - |transform_1| Learn to find the Fourier Transform of images - - - ============= =================================================================== - - .. |transform_1| image:: images/transform_fourier.jpg - :height: 90pt - :width: 90pt - - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_fourier_transform/py_fourier_transform diff --git a/doc/py_tutorials/py_imgproc/py_watershed/py_watershed.rst b/doc/py_tutorials/py_imgproc/py_watershed/py_watershed.rst deleted file mode 100644 index e8a57721d6..0000000000 --- a/doc/py_tutorials/py_imgproc/py_watershed/py_watershed.rst +++ /dev/null @@ -1,121 +0,0 @@ -.. _Watershed: - -Image Segmentation with Watershed Algorithm -********************************************* - -Goal -===== - -In this chapter, - * We will learn to use marker-based image segmentation using watershed algorithm - * We will see: **cv2.watershed()** - -Theory -======== - -Any grayscale image can be viewed as a topographic surface where high intensity denotes peaks and hills while low intensity denotes valleys. You start filling every isolated valleys (local minima) with different colored water (labels). As the water rises, depending on the peaks (gradients) nearby, water from different valleys, obviously with different colors will start to merge. To avoid that, you build barriers in the locations where water merges. You continue the work of filling water and building barriers until all the peaks are under water. Then the barriers you created gives you the segmentation result. This is the "philosophy" behind the watershed. You can visit the `CMM webpage on watershed `_ to understand it with the help of some animations. - -But this approach gives you oversegmented result due to noise or any other irregularities in the image. So OpenCV implemented a marker-based watershed algorithm where you specify which are all valley points are to be merged and which are not. It is an interactive image segmentation. What we do is to give different labels for our object we know. Label the region which we are sure of being the foreground or object with one color (or intensity), label the region which we are sure of being background or non-object with another color and finally the region which we are not sure of anything, label it with 0. That is our marker. Then apply watershed algorithm. Then our marker will be updated with the labels we gave, and the boundaries of objects will have a value of -1. - -Code -======== - -Below we will see an example on how to use the Distance Transform along with watershed to segment mutually touching objects. - -Consider the coins image below, the coins are touching each other. Even if you threshold it, it will be touching each other. - - .. image:: images/water_coins.jpg - :alt: Coins - :align: center - -We start with finding an approximate estimate of the coins. For that, we can use the Otsu's binarization. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img = cv2.imread('coins.png') - gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) - -Result: - - .. image:: images/water_thresh.jpg - :alt: Thresholding - :align: center - -Now we need to remove any small white noises in the image. For that we can use morphological opening. To remove any small holes in the object, we can use morphological closing. So, now we know for sure that region near to center of objects are foreground and region much away from the object are background. Only region we are not sure is the boundary region of coins. - -So we need to extract the area which we are sure they are coins. Erosion removes the boundary pixels. So whatever remaining, we can be sure it is coin. That would work if objects were not touching each other. But since they are touching each other, another good option would be to find the distance transform and apply a proper threshold. Next we need to find the area which we are sure they are not coins. For that, we dilate the result. Dilation increases object boundary to background. This way, we can make sure whatever region in background in result is really a background, since boundary region is removed. See the image below. - - .. image:: images/water_fgbg.jpg - :alt: Foreground and Background - :align: center - -The remaining regions are those which we don't have any idea, whether it is coins or background. Watershed algorithm should find it. These areas are normally around the boundaries of coins where foreground and background meet (Or even two different coins meet). We call it border. It can be obtained from subtracting sure_fg area from sure_bg area. -:: - - # noise removal - kernel = np.ones((3,3),np.uint8) - opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2) - - # sure background area - sure_bg = cv2.dilate(opening,kernel,iterations=3) - - # Finding sure foreground area - dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5) - ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0) - - # Finding unknown region - sure_fg = np.uint8(sure_fg) - unknown = cv2.subtract(sure_bg,sure_fg) - -See the result. In the thresholded image, we get some regions of coins which we are sure of coins and they are detached now. (In some cases, you may be interested in only foreground segmentation, not in separating the mutually touching objects. In that case, you need not use distance transform, just erosion is sufficient. Erosion is just another method to extract sure foreground area, that's all.) - - .. image:: images/water_dt.jpg - :alt: Distance Transform - :align: center - -Now we know for sure which are region of coins, which are background and all. So we create marker (it is an array of same size as that of original image, but with int32 datatype) and label the regions inside it. The regions we know for sure (whether foreground or background) are labelled with any positive integers, but different integers, and the area we don't know for sure are just left as zero. For this we use **cv2.connectedComponents()**. It labels background of the image with 0, then other objects are labelled with integers starting from 1. - -But we know that if background is marked with 0, watershed will consider it as unknown area. So we want to mark it with different integer. Instead, we will mark unknown region, defined by ``unknown``, with 0. -:: - - # Marker labelling - ret, markers = cv2.connectedComponents(sure_fg) - - # Add one to all labels so that sure background is not 0, but 1 - markers = markers+1 - - # Now, mark the region of unknown with zero - markers[unknown==255] = 0 - -See the result shown in JET colormap. The dark blue region shows unknown region. Sure coins are colored with different values. Remaining area which are sure background are shown in lighter blue compared to unknown region. - - .. image:: images/water_marker.jpg - :alt: Marker Image - :align: center - -Now our marker is ready. It is time for final step, apply watershed. Then marker image will be modified. The boundary region will be marked with -1. -:: - - markers = cv2.watershed(img,markers) - img[markers == -1] = [255,0,0] - -See the result below. For some coins, the region where they touch are segmented properly and for some, they are not. - - .. image:: images/water_result.jpg - :alt: Result - :align: center - - -Additional Resources -====================== - -#. CMM page on `Watershed Tranformation `_ - -Exercises -============== - -#. OpenCV samples has an interactive sample on watershed segmentation, `watershed.py`. Run it, Enjoy it, then learn it. diff --git a/doc/py_tutorials/py_ml/py_table_of_contents_ml/images/kmeansicon.jpg b/doc/py_tutorials/py_ml/images/kmeansicon.jpg similarity index 100% rename from doc/py_tutorials/py_ml/py_table_of_contents_ml/images/kmeansicon.jpg rename to doc/py_tutorials/py_ml/images/kmeansicon.jpg diff --git a/doc/py_tutorials/py_ml/py_table_of_contents_ml/images/knnicon.png b/doc/py_tutorials/py_ml/images/knnicon.png similarity index 100% rename from doc/py_tutorials/py_ml/py_table_of_contents_ml/images/knnicon.png rename to doc/py_tutorials/py_ml/images/knnicon.png diff --git a/doc/py_tutorials/py_ml/py_table_of_contents_ml/images/svmicon.png b/doc/py_tutorials/py_ml/images/svmicon.png similarity index 100% rename from doc/py_tutorials/py_ml/py_table_of_contents_ml/images/svmicon.png rename to doc/py_tutorials/py_ml/images/svmicon.png diff --git a/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_index.rst b/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_index.rst deleted file mode 100644 index 55586e86d5..0000000000 --- a/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_index.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. _KMeans_Clustering: - -K-Means Clustering -********************* - -* :ref:`KMeans_Clustering_Understanding` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |KM_1| Read to get an intuitive understanding of K-Means Clustering - =========== =================================================================== - - .. |KM_1| image:: images/kmeans_begin.jpg - :height: 90pt - :width: 90pt - -* :ref:`KMeans_OpenCV` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |KM_2| Now let's try K-Means functions in OpenCV - =========== =================================================================== - - .. |KM_2| image:: images/kmeans_demo.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - py_kmeans_understanding/py_kmeans_understanding - py_kmeans_opencv/py_kmeans_opencv diff --git a/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.rst b/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.rst deleted file mode 100644 index 33199c03a0..0000000000 --- a/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.rst +++ /dev/null @@ -1,192 +0,0 @@ -.. _KMeans_OpenCV: - -K-Means Clustering in OpenCV -****************************** - -Goal -======= - - * Learn to use **cv2.kmeans()** function in OpenCV for data clustering - -Understanding Parameters -========================== - -Input parameters ------------------- - 1. **samples** : It should be of **np.float32** data type, and each feature should be put in a single column. - - 2. **nclusters(K)** : Number of clusters required at end - - 3. **criteria** : It is the iteration termination criteria. When this criteria is satisfied, algorithm iteration stops. Actually, it should be a tuple of 3 parameters. They are ``( type, max_iter, epsilon )``: - * 3.a - type of termination criteria : It has 3 flags as below: - **cv2.TERM_CRITERIA_EPS** - stop the algorithm iteration if specified accuracy, *epsilon*, is reached. - **cv2.TERM_CRITERIA_MAX_ITER** - stop the algorithm after the specified number of iterations, *max_iter*. - **cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER** - stop the iteration when any of the above condition is met. - - * 3.b - max_iter - An integer specifying maximum number of iterations. - * 3.c - epsilon - Required accuracy - - 4. **attempts** : Flag to specify the number of times the algorithm is executed using different initial labellings. The algorithm returns the labels that yield the best compactness. This compactness is returned as output. - - 5. **flags** : This flag is used to specify how initial centers are taken. Normally two flags are used for this : **cv2.KMEANS_PP_CENTERS** and **cv2.KMEANS_RANDOM_CENTERS**. - -Output parameters --------------------- - 1. **compactness** : It is the sum of squared distance from each point to their corresponding centers. - - 2. **labels** : This is the label array (same as 'code' in previous article) where each element marked '0', '1'..... - - 3. **centers** : This is array of centers of clusters. - -Now we will see how to apply K-Means algorithm with three examples. - -1. Data with Only One Feature -=============================== - -Consider, you have a set of data with only one feature, ie one-dimensional. For eg, we can take our t-shirt problem where you use only height of people to decide the size of t-shirt. - -So we start by creating data and plot it in Matplotlib -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - x = np.random.randint(25,100,25) - y = np.random.randint(175,255,25) - z = np.hstack((x,y)) - z = z.reshape((50,1)) - z = np.float32(z) - plt.hist(z,256,[0,256]),plt.show() - -So we have 'z' which is an array of size 50, and values ranging from 0 to 255. I have reshaped 'z' to a column vector. It will be more useful when more than one features are present. Then I made data of np.float32 type. - -We get following image : - - .. image:: images/oc_1d_testdata.png - :alt: Test Data - :align: center - -Now we apply the KMeans function. Before that we need to specify the `criteria`. My criteria is such that, whenever 10 iterations of algorithm is ran, or an accuracy of ``epsilon = 1.0`` is reached, stop the algorithm and return the answer. -:: - - # Define criteria = ( type, max_iter = 10 , epsilon = 1.0 ) - criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) - - # Set flags (Just to avoid line break in the code) - flags = cv2.KMEANS_RANDOM_CENTERS - - # Apply KMeans - compactness,labels,centers = cv2.kmeans(z,2,None,criteria,10,flags) - -This gives us the compactness, labels and centers. In this case, I got centers as 60 and 207. Labels will have the same size as that of test data where each data will be labelled as '0','1','2' etc. depending on their centroids. Now we split the data to different clusters depending on their labels. -:: - - A = z[labels==0] - B = z[labels==1] - -Now we plot A in Red color and B in Blue color and their centroids in Yellow color. -:: - - # Now plot 'A' in red, 'B' in blue, 'centers' in yellow - plt.hist(A,256,[0,256],color = 'r') - plt.hist(B,256,[0,256],color = 'b') - plt.hist(centers,32,[0,256],color = 'y') - plt.show() - -Below is the output we got: - - .. image:: images/oc_1d_clustered.png - :alt: Result of KMeans Clustering - :align: center - -2. Data with Multiple Features -=============================== - -In previous example, we took only height for t-shirt problem. Here, we will take both height and weight, ie two features. - -Remember, in previous case, we made our data to a single column vector. Each feature is arranged in a column, while each row corresponds to an input test sample. - -For example, in this case, we set a test data of size 50x2, which are heights and weights of 50 people. First column corresponds to height of all the 50 people and second column corresponds to their weights. First row contains two elements where first one is the height of first person and second one his weight. Similarly remaining rows corresponds to heights and weights of other people. Check image below: - - .. image:: images/oc_feature_representation.jpg - :alt: Feature Representation - :align: center - -Now I am directly moving to the code: -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - X = np.random.randint(25,50,(25,2)) - Y = np.random.randint(60,85,(25,2)) - Z = np.vstack((X,Y)) - - # convert to np.float32 - Z = np.float32(Z) - - # define criteria and apply kmeans() - criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) - ret,label,center=cv2.kmeans(Z,2,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS) - - # Now separate the data, Note the flatten() - A = Z[label.ravel()==0] - B = Z[label.ravel()==1] - - # Plot the data - plt.scatter(A[:,0],A[:,1]) - plt.scatter(B[:,0],B[:,1],c = 'r') - plt.scatter(center[:,0],center[:,1],s = 80,c = 'y', marker = 's') - plt.xlabel('Height'),plt.ylabel('Weight') - plt.show() - -Below is the output we get: - - .. image:: images/oc_2d_clustered.jpg - :alt: Result of KMeans Clustering - :align: center - -3. Color Quantization -======================= - -Color Quantization is the process of reducing number of colors in an image. One reason to do so is to reduce the memory. Sometimes, some devices may have limitation such that it can produce only limited number of colors. In those cases also, color quantization is performed. Here we use k-means clustering for color quantization. - -There is nothing new to be explained here. There are 3 features, say, R,G,B. So we need to reshape the image to an array of Mx3 size (M is number of pixels in image). And after the clustering, we apply centroid values (it is also R,G,B) to all pixels, such that resulting image will have specified number of colors. And again we need to reshape it back to the shape of original image. Below is the code: -:: - - import numpy as np - import cv2 - - img = cv2.imread('home.jpg') - Z = img.reshape((-1,3)) - - # convert to np.float32 - Z = np.float32(Z) - - # define criteria, number of clusters(K) and apply kmeans() - criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) - K = 8 - ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS) - - # Now convert back into uint8, and make original image - center = np.uint8(center) - res = center[label.flatten()] - res2 = res.reshape((img.shape)) - - cv2.imshow('res2',res2) - cv2.waitKey(0) - cv2.destroyAllWindows() - -See the result below for K=8: - - .. image:: images/oc_color_quantization.jpg - :alt: Color Quantization - :align: center - -Additional Resources -======================= - -Exercises -============= diff --git a/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_understanding/py_kmeans_understanding.rst b/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_understanding/py_kmeans_understanding.rst deleted file mode 100644 index 63bbfcdda5..0000000000 --- a/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_understanding/py_kmeans_understanding.rst +++ /dev/null @@ -1,81 +0,0 @@ -.. _KMeans_Clustering_Understanding: - -Understanding K-Means Clustering -*********************************** - -Goal -===== - -In this chapter, we will understand the concepts of K-Means Clustering, how it works etc. - -Theory -======= - -We will deal this with an example which is commonly used. - -T-shirt size problem ------------------------- - -Consider a company, which is going to release a new model of T-shirt to market. Obviously they will have to manufacture models in different sizes to satisfy people of all sizes. So the company make a data of people's height and weight, and plot them on to a graph, as below: - - .. image:: images/tshirt.jpg - :alt: T-shirt Problem - :align: center - -Company can't create t-shirts with all the sizes. Instead, they divide people to Small, Medium and Large, and manufacture only these 3 models which will fit into all the people. This grouping of people into three groups can be done by k-means clustering, and algorithm provides us best 3 sizes, which will satisfy all the people. And if it doesn't, company can divide people to more groups, may be five, and so on. Check image below : - - .. image:: images/tshirt_grouped.jpg - :alt: People Grouped into Different Sizes - :align: center - -How does it work ? ------------------------------- - -This algorithm is an iterative process. We will explain it step-by-step with the help of images. - -Consider a set of data as below ( You can consider it as t-shirt problem). We need to cluster this data into two groups. - - .. image:: images/testdata.jpg - :alt: Test Data - :align: center - -**Step : 1** - Algorithm randomly chooses two centroids, :math:`C1` and :math:`C2` (sometimes, any two data are taken as the centroids). - -**Step : 2** - It calculates the distance from each point to both centroids. If a test data is more closer to :math:`C1`, then that data is labelled with '0'. If it is closer to :math:`C2`, then labelled as '1' (If more centroids are there, labelled as '2','3' etc). - -In our case, we will color all '0' labelled with red, and '1' labelled with blue. So we get following image after above operations. - - .. image:: images/initial_labelling.jpg - :alt: Initial Centroid Selection and Data Collection - :align: center - -**Step : 3** - Next we calculate the average of all blue points and red points separately and that will be our new centroids. That is :math:`C1` and :math:`C2` shift to newly calculated centroids. (Remember, the images shown are not true values and not to true scale, it is just for demonstration only). - -And again, perform step 2 with new centroids and label data to '0' and '1'. - -So we get result as below : - - .. image:: images/update_centroid.jpg - :alt: New Centroid Calculated and Data Re-laballed - :align: center - -Now **Step - 2** and **Step - 3** are iterated until both centroids are converged to fixed points. *(Or it may be stopped depending on the criteria we provide, like maximum number of iterations, or a specific accuracy is reached etc.)* **These points are such that sum of distances between test data and their corresponding centroids are minimum**. Or simply, sum of distances between :math:`C1 \leftrightarrow Red\_Points` and :math:`C2 \leftrightarrow Blue\_Points` is minimum. - -.. math:: - - minimize \;\bigg[J = \sum_{All\: Red_Points}distance(C1,Red\_Point) + \sum_{All\: Blue\_Points}distance(C2,Blue\_Point)\bigg] - -Final result almost looks like below : - - .. image:: images/final_clusters.jpg - :alt: Final Result - :align: center - -So this is just an intuitive understanding of K-Means Clustering. For more details and mathematical explanation, please read any standard machine learning textbooks or check links in additional resources. It is just a top layer of K-Means clustering. There are a lot of modifications to this algorithm like, how to choose the initial centroids, how to speed up the iteration process etc. - -Additional Resources -===================== -#. `Machine Learning Course `_, Video lectures by Prof. Andrew Ng (Some of the images are taken from this) - -Exercises -=========== diff --git a/doc/py_tutorials/py_ml/py_knn/py_knn_index.rst b/doc/py_tutorials/py_ml/py_knn/py_knn_index.rst deleted file mode 100644 index c90634b304..0000000000 --- a/doc/py_tutorials/py_ml/py_knn/py_knn_index.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. _KNN: - -K-Nearest Neighbour -********************** - -* :ref:`KNN_Understanding` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |KNN_1| Get a basic understanding of what kNN is - =========== =================================================================== - - .. |KNN_1| image:: images/knn_icon1.jpg - :height: 90pt - :width: 90pt - -* :ref:`KNN_OpenCV` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |KNN_2| Now let's use kNN in OpenCV for digit recognition OCR - =========== =================================================================== - - .. |KNN_2| image:: images/knn_icon2.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - py_knn_understanding/py_knn_understanding - py_knn_opencv/py_knn_opencv diff --git a/doc/py_tutorials/py_ml/py_knn/py_knn_opencv/py_knn_opencv.rst b/doc/py_tutorials/py_ml/py_knn/py_knn_opencv/py_knn_opencv.rst deleted file mode 100644 index 8780d49416..0000000000 --- a/doc/py_tutorials/py_ml/py_knn/py_knn_opencv/py_knn_opencv.rst +++ /dev/null @@ -1,107 +0,0 @@ -.. _KNN_OpenCV: - -OCR of Hand-written Data using kNN -*********************************************** - -Goal -======= - -In this chapter - * We will use our knowledge on kNN to build a basic OCR application. - * We will try with Digits and Alphabets data available that comes with OpenCV. - - -OCR of Hand-written Digits -============================ - -Our goal is to build an application which can read the handwritten digits. For this we need some train_data and test_data. OpenCV comes with an image `digits.png` (in the folder ``opencv/samples/python2/data/``) which has 5000 handwritten digits (500 for each digit). Each digit is a 20x20 image. So our first step is to split this image into 5000 different digits. For each digit, we flatten it into a single row with 400 pixels. That is our feature set, ie intensity values of all pixels. It is the simplest feature set we can create. We use first 250 samples of each digit as train_data, and next 250 samples as test_data. So let's prepare them first. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img = cv2.imread('digits.png') - gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) - - # Now we split the image to 5000 cells, each 20x20 size - cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)] - - # Make it into a Numpy array. It size will be (50,100,20,20) - x = np.array(cells) - - # Now we prepare train_data and test_data. - train = x[:,:50].reshape(-1,400).astype(np.float32) # Size = (2500,400) - test = x[:,50:100].reshape(-1,400).astype(np.float32) # Size = (2500,400) - - # Create labels for train and test data - k = np.arange(10) - train_labels = np.repeat(k,250)[:,np.newaxis] - test_labels = train_labels.copy() - - # Initiate kNN, train the data, then test it with test data for k=1 - knn = cv2.KNearest() - knn.train(train,train_labels) - ret,result,neighbours,dist = knn.find_nearest(test,k=5) - - # Now we check the accuracy of classification - # For that, compare the result with test_labels and check which are wrong - matches = result==test_labels - correct = np.count_nonzero(matches) - accuracy = correct*100.0/result.size - print accuracy - - -So our basic OCR app is ready. This particular example gave me an accuracy of 91%. One option improve accuracy is to add more data for training, especially the wrong ones. So instead of finding this training data everytime I start application, I better save it, so that next time, I directly read this data from a file and start classification. You can do it with the help of some Numpy functions like np.savetxt, np.savez, np.load etc. Please check their docs for more details. -:: - - # save the data - np.savez('knn_data.npz',train=train, train_labels=train_labels) - - # Now load the data - with np.load('knn_data.npz') as data: - print data.files - train = data['train'] - train_labels = data['train_labels'] - -In my system, it takes around 4.4 MB of memory. Since we are using intensity values (uint8 data) as features, it would be better to convert the data to np.uint8 first and then save it. It takes only 1.1 MB in this case. Then while loading, you can convert back into float32. - -OCR of English Alphabets -=========================== - -Next we will do the same for English alphabets, but there is a slight change in data and feature set. Here, instead of images, OpenCV comes with a data file, ``letter-recognition.data`` in ``opencv/samples/cpp/`` folder. If you open it, you will see 20000 lines which may, on first sight, look like garbage. Actually, in each row, first column is an alphabet which is our label. Next 16 numbers following it are its different features. These features are obtained from `UCI Machine Learning Repository `_. You can find the details of these features in `this page `_. - -There are 20000 samples available, so we take first 10000 data as training samples and remaining 10000 as test samples. We should change the alphabets to ascii characters because we can't work with alphabets directly. -:: - - import cv2 - import numpy as np - import matplotlib.pyplot as plt - - # Load the data, converters convert the letter to a number - data= np.loadtxt('letter-recognition.data', dtype= 'float32', delimiter = ',', - converters= {0: lambda ch: ord(ch)-ord('A')}) - - # split the data to two, 10000 each for train and test - train, test = np.vsplit(data,2) - - # split trainData and testData to features and responses - responses, trainData = np.hsplit(train,[1]) - labels, testData = np.hsplit(test,[1]) - - # Initiate the kNN, classify, measure accuracy. - knn = cv2.KNearest() - knn.train(trainData, responses) - ret, result, neighbours, dist = knn.find_nearest(testData, k=5) - - correct = np.count_nonzero(result == labels) - accuracy = correct*100.0/10000 - print accuracy - -It gives me an accuracy of 93.22%. Again, if you want to increase accuracy, you can iteratively add error data in each level. - -Additional Resources -======================= - -Exercises -============= diff --git a/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.rst b/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.rst deleted file mode 100644 index 22f51539ab..0000000000 --- a/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.rst +++ /dev/null @@ -1,121 +0,0 @@ -.. _KNN_Understanding: - -Understanding k-Nearest Neighbour -*********************************** - -Goal -===== - -In this chapter, we will understand the concepts of k-Nearest Neighbour (kNN) algorithm. - -Theory -======= - -kNN is one of the simplest of classification algorithms available for supervised learning. The idea is to search for closest match of the test data in feature space. We will look into it with below image. - - .. image:: images/knn_theory.png - :alt: Understanding kNN - :align: center - -In the image, there are two families, `Blue Squares and Red Triangles`. We call each family as **Class**. Their houses are shown in their town map which we call `feature space`. *(You can consider a feature space as a space where all datas are projected. For example, consider a 2D coordinate space. Each data has two features, x and y coordinates. You can represent this data in your 2D coordinate space, right? Now imagine if there are three features, you need 3D space. Now consider N features, where you need N-dimensional space, right? This N-dimensional space is its feature space. In our image, you can consider it as a 2D case with two features)*. - -Now a new member comes into the town and creates a new home, which is shown as green circle. He should be added to one of these Blue/Red families. We call that process, **Classification**. What we do? Since we are dealing with kNN, let us apply this algorithm. - -One method is to check who is his nearest neighbour. From the image, it is clear it is the Red Triangle family. So he is also added into Red Triangle. This method is called simply **Nearest Neighbour**, because classification depends only on the nearest neighbour. - -But there is a problem with that. Red Triangle may be the nearest. But what if there are lot of Blue Squares near to him? Then Blue Squares have more strength in that locality than Red Triangle. So just checking nearest one is not sufficient. Instead we check some `k` nearest families. Then whoever is majority in them, the new guy belongs to that family. In our image, let's take `k=3`, ie 3 nearest families. He has two Red and one Blue (there are two Blues equidistant, but since k=3, we take only one of them), so again he should be added to Red family. But what if we take `k=7`? Then he has 5 Blue families and 2 Red families. Great!! Now he should be added to Blue family. So it all changes with value of k. More funny thing is, what if `k = 4`? He has 2 Red and 2 Blue neighbours. It is a tie !!! So better take k as an odd number. So this method is called **k-Nearest Neighbour** since classification depends on k nearest neighbours. - -Again, in kNN, it is true we are considering k neighbours, but we are giving equal importance to all, right? Is it justice? For example, take the case of `k=4`. We told it is a tie. But see, the 2 Red families are more closer to him than the other 2 Blue families. So he is more eligible to be added to Red. So how do we mathematically explain that? We give some weights to each family depending on their distance to the new-comer. For those who are near to him get higher weights while those are far away get lower weights. Then we add total weights of each family separately. Whoever gets highest total weights, new-comer goes to that family. This is called **modified kNN**. - -So what are some important things you see here? - - * You need to have information about all the houses in town, right? Because, we have to check the distance from new-comer to all the existing houses to find the nearest neighbour. If there are plenty of houses and families, it takes lots of memory, and more time for calculation also. - * There is almost zero time for any kind of training or preparation. - -Now let's see it in OpenCV. - -kNN in OpenCV -=============== - -We will do a simple example here, with two families (classes), just like above. Then in the next chapter, we will do an even better example. - -So here, we label the Red family as **Class-0** (so denoted by 0) and Blue family as **Class-1** (denoted by 1). We create 25 families or 25 training data, and label them either Class-0 or Class-1. We do all these with the help of Random Number Generator in Numpy. - -Then we plot it with the help of Matplotlib. Red families are shown as Red Triangles and Blue families are shown as Blue Squares. -:: - - import cv2 - import numpy as np - import matplotlib.pyplot as plt - - # Feature set containing (x,y) values of 25 known/training data - trainData = np.random.randint(0,100,(25,2)).astype(np.float32) - - # Labels each one either Red or Blue with numbers 0 and 1 - responses = np.random.randint(0,2,(25,1)).astype(np.float32) - - # Take Red families and plot them - red = trainData[responses.ravel()==0] - plt.scatter(red[:,0],red[:,1],80,'r','^') - - # Take Blue families and plot them - blue = trainData[responses.ravel()==1] - plt.scatter(blue[:,0],blue[:,1],80,'b','s') - - plt.show() - -You will get something similar to our first image. Since you are using random number generator, you will be getting different data each time you run the code. - -Next initiate the kNN algorithm and pass the `trainData` and `responses` to train the kNN (It constructs a search tree). - -Then we will bring one new-comer and classify him to a family with the help of kNN in OpenCV. Before going to kNN, we need to know something on our test data (data of new comers). Our data should be a floating point array with size :math:`number \; of \; testdata \times number \; of \; features`. Then we find the nearest neighbours of new-comer. We can specify how many neighbours we want. It returns: - - 1. The label given to new-comer depending upon the kNN theory we saw earlier. If you want Nearest Neighbour algorithm, just specify `k=1` where k is the number of neighbours. - 2. The labels of k-Nearest Neighbours. - 3. Corresponding distances from new-comer to each nearest neighbour. - -So let's see how it works. New comer is marked in green color. -:: - - newcomer = np.random.randint(0,100,(1,2)).astype(np.float32) - plt.scatter(newcomer[:,0],newcomer[:,1],80,'g','o') - - knn = cv2.KNearest() - knn.train(trainData,responses) - ret, results, neighbours ,dist = knn.find_nearest(newcomer, 3) - - print "result: ", results,"\n" - print "neighbours: ", neighbours,"\n" - print "distance: ", dist - - plt.show() - -I got the result as follows: -:: - - result: [[ 1.]] - neighbours: [[ 1. 1. 1.]] - distance: [[ 53. 58. 61.]] - -It says our new-comer got 3 neighbours, all from Blue family. Therefore, he is labelled as Blue family. It is obvious from plot below: - - .. image:: images/knn_simple.png - :alt: kNN Demo - :align: center - -If you have large number of data, you can just pass it as array. Corresponding results are also obtained as arrays. -:: - - # 10 new comers - newcomers = np.random.randint(0,100,(10,2)).astype(np.float32) - ret, results,neighbours,dist = knn.find_nearest(newcomer, 3) - # The results also will contain 10 labels. - - -Additional Resources -====================== - -#. `NPTEL notes on Pattern Recognition, Chapter 11 `_ - -Exercises -=========== diff --git a/doc/py_tutorials/py_ml/py_svm/py_svm_basics/py_svm_basics.rst b/doc/py_tutorials/py_ml/py_svm/py_svm_basics/py_svm_basics.rst deleted file mode 100644 index a54437839b..0000000000 --- a/doc/py_tutorials/py_ml/py_svm/py_svm_basics/py_svm_basics.rst +++ /dev/null @@ -1,103 +0,0 @@ -.. _SVM_Understanding: - -Understanding SVM -******************** - -Goal -====== - -In this chapter - * We will see an intuitive understanding of SVM - - -Theory -========== - -Linearly Separable Data ---------------------------- - -Consider the image below which has two types of data, red and blue. In kNN, for a test data, we used to measure its distance to all the training samples and take the one with minimum distance. It takes plenty of time to measure all the distances and plenty of memory to store all the training-samples. But considering the data given in image, should we need that much? - - .. image:: images/svm_basics1.png - :alt: Test Data - :align: center - -Consider another idea. We find a line, :math:`f(x)=ax_1+bx_2+c` which divides both the data to two regions. When we get a new test_data :math:`X`, just substitute it in :math:`f(x)`. If :math:`f(X) > 0`, it belongs to blue group, else it belongs to red group. We can call this line as **Decision Boundary**. It is very simple and memory-efficient. Such data which can be divided into two with a straight line (or hyperplanes in higher dimensions) is called **Linear Separable**. - -So in above image, you can see plenty of such lines are possible. Which one we will take? Very intuitively we can say that the line should be passing as far as possible from all the points. Why? Because there can be noise in the incoming data. This data should not affect the classification accuracy. So taking a farthest line will provide more immunity against noise. So what SVM does is to find a straight line (or hyperplane) with largest minimum distance to the training samples. See the bold line in below image passing through the center. - - .. image:: images/svm_basics2.png - :alt: Decision Boundary - :align: center - -So to find this Decision Boundary, you need training data. Do you need all? NO. Just the ones which are close to the opposite group are sufficient. In our image, they are the one blue filled circle and two red filled squares. We can call them **Support Vectors** and the lines passing through them are called **Support Planes**. They are adequate for finding our decision boundary. We need not worry about all the data. It helps in data reduction. - -What happened is, first two hyperplanes are found which best represents the data. For eg, blue data is represented by :math:`w^Tx+b_0 > 1` while red data is represented by :math:`w^Tx+b_0 < -1` where :math:`w` is **weight vector** ( :math:`w=[w_1, w_2,..., w_n]`) and :math:`x` is the feature vector (:math:`x = [x_1,x_2,..., x_n]`). :math:`b_0` is the **bias**. Weight vector decides the orientation of decision boundary while bias point decides its location. Now decision boundary is defined to be midway between these hyperplanes, so expressed as :math:`w^Tx+b_0 = 0`. The minimum distance from support vector to the decision boundary is given by, :math:`distance_{support \, vectors}=\frac{1}{||w||}`. Margin is twice this distance, and we need to maximize this margin. i.e. we need to minimize a new function :math:`L(w, b_0)` with some constraints which can expressed below: - -.. math:: - - \min_{w, b_0} L(w, b_0) = \frac{1}{2}||w||^2 \; \text{subject to} \; t_i(w^Tx+b_0) \geq 1 \; \forall i - -where :math:`t_i` is the label of each class, :math:`t_i \in [-1,1]`. - - - -Non-Linearly Separable Data ------------------------------ - -Consider some data which can't be divided into two with a straight line. For example, consider an one-dimensional data where 'X' is at -3 & +3 and 'O' is at -1 & +1. Clearly it is not linearly separable. But there are methods to solve these kinds of problems. If we can map this data set with a function, :math:`f(x) = x^2`, we get 'X' at 9 and 'O' at 1 which are linear separable. - -Otherwise we can convert this one-dimensional to two-dimensional data. We can use :math:`f(x)=(x,x^2)` function to map this data. Then 'X' becomes (-3,9) and (3,9) while 'O' becomes (-1,1) and (1,1). This is also linear separable. In short, chance is more for a non-linear separable data in lower-dimensional space to become linear separable in higher-dimensional space. - -In general, it is possible to map points in a d-dimensional space to some D-dimensional space :math:`(D>d)` to check the possibility of linear separability. There is an idea which helps to compute the dot product in the high-dimensional (kernel) space by performing computations in the low-dimensional input (feature) space. We can illustrate with following example. - -Consider two points in two-dimensional space, :math:`p=(p_1,p_2)` and :math:`q=(q_1,q_2)`. Let :math:`\phi` be a mapping function which maps a two-dimensional point to three-dimensional space as follows: - -.. math:: - - \phi (p) = (p_{1}^2,p_{2}^2,\sqrt{2} p_1 p_2) - \phi (q) = (q_{1}^2,q_{2}^2,\sqrt{2} q_1 q_2) - -Let us define a kernel function :math:`K(p,q)` which does a dot product between two points, shown below: - -.. math:: - - K(p,q) = \phi(p).\phi(q) &= \phi(p)^T \phi(q) \\ - &= (p_{1}^2,p_{2}^2,\sqrt{2} p_1 p_2).(q_{1}^2,q_{2}^2,\sqrt{2} q_1 q_2) \\ - &= p_1 q_1 + p_2 q_2 + 2 p_1 q_1 p_2 q_2 \\ - &= (p_1 q_1 + p_2 q_2)^2 \\ - \phi(p).\phi(q) &= (p.q)^2 - -It means, a dot product in three-dimensional space can be achieved using squared dot product in two-dimensional space. This can be applied to higher dimensional space. So we can calculate higher dimensional features from lower dimensions itself. Once we map them, we get a higher dimensional space. - -In addition to all these concepts, there comes the problem of misclassification. So just finding decision boundary with maximum margin is not sufficient. We need to consider the problem of misclassification errors also. Sometimes, it may be possible to find a decision boundary with less margin, but with reduced misclassification. Anyway we need to modify our model such that it should find decision boundary with maximum margin, but with less misclassification. The minimization criteria is modified as: - -.. math:: - - min \; ||w||^2 + C(distance \; of \; misclassified \; samples \; to \; their \; correct \; regions) - -Below image shows this concept. For each sample of the training data a new parameter :math:`\xi_i` is defined. It is the distance from its corresponding training sample to their correct decision region. For those who are not misclassified, they fall on their corresponding support planes, so their distance is zero. - - .. image:: images/svm_basics3.png - :alt: Misclassification - :align: center - -So the new optimization problem is : - -.. math:: - - \min_{w, b_{0}} L(w,b_0) = ||w||^{2} + C \sum_{i} {\xi_{i}} \text{ subject to } y_{i}(w^{T} x_{i} + b_{0}) \geq 1 - \xi_{i} \text{ and } \xi_{i} \geq 0 \text{ } \forall i - -How should the parameter C be chosen? It is obvious that the answer to this question depends on how the training data is distributed. Although there is no general answer, it is useful to take into account these rules: - - * Large values of C give solutions with less misclassification errors but a smaller margin. Consider that in this case it is expensive to make misclassification errors. Since the aim of the optimization is to minimize the argument, few misclassifications errors are allowed. - * Small values of C give solutions with bigger margin and more classification errors. In this case the minimization does not consider that much the term of the sum so it focuses more on finding a hyperplane with big margin. - -Additional Resources -====================== - -#. `NPTEL notes on Statistical Pattern Recognition, Chapters 25-29 `_. - - -Exercises -=========== diff --git a/doc/py_tutorials/py_ml/py_svm/py_svm_index.rst b/doc/py_tutorials/py_ml/py_svm/py_svm_index.rst deleted file mode 100644 index 5ee69affdf..0000000000 --- a/doc/py_tutorials/py_ml/py_svm/py_svm_index.rst +++ /dev/null @@ -1,42 +0,0 @@ -.. _SVM: - -Support Vector Machines (SVM) -******************************** - -* :ref:`SVM_Understanding` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |SVM_1| Get a basic understanding of what SVM is - =========== =================================================================== - - .. |SVM_1| image:: images/svm_icon1.jpg - :height: 90pt - :width: 90pt - - -* :ref:`svm_opencv` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |SVM_2| Let's use SVM functionalities in OpenCV - =========== =================================================================== - - .. |SVM_2| image:: images/svm_icon2.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - py_svm_basics/py_svm_basics - py_svm_opencv/py_svm_opencv diff --git a/doc/py_tutorials/py_ml/py_svm/py_svm_opencv/py_svm_opencv.rst b/doc/py_tutorials/py_ml/py_svm/py_svm_opencv/py_svm_opencv.rst deleted file mode 100644 index 73c7c9fe3a..0000000000 --- a/doc/py_tutorials/py_ml/py_svm/py_svm_opencv/py_svm_opencv.rst +++ /dev/null @@ -1,134 +0,0 @@ -.. _svm_opencv: - - -OCR of Hand-written Data using SVM -*********************************************** - -Goal -========= - -In this chapter - - * We will revisit the hand-written data OCR, but, with SVM instead of kNN. - - -OCR of Hand-written Digits -============================ - -In kNN, we directly used pixel intensity as the feature vector. This time we will use `Histogram of Oriented Gradients `_ (HOG) as feature vectors. - -Here, before finding the HOG, we deskew the image using its second order moments. So we first define a function **deskew()** which takes a digit image and deskew it. Below is the deskew() function: -:: - - def deskew(img): - m = cv2.moments(img) - if abs(m['mu02']) < 1e-2: - return img.copy() - skew = m['mu11']/m['mu02'] - M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]]) - img = cv2.warpAffine(img,M,(SZ, SZ),flags=affine_flags) - return img - -Below image shows above deskew function applied to an image of zero. Left image is the original image and right image is the deskewed image. - - .. image:: images/deskew.jpg - :alt: Deskew - :align: center - - -Next we have to find the HOG Descriptor of each cell. For that, we find Sobel derivatives of each cell in X and Y direction. Then find their magnitude and direction of gradient at each pixel. This gradient is quantized to 16 integer values. Divide this image to four sub-squares. For each sub-square, calculate the histogram of direction (16 bins) weighted with their magnitude. So each sub-square gives you a vector containing 16 values. Four such vectors (of four sub-squares) together gives us a feature vector containing 64 values. This is the feature vector we use to train our data. -:: - - def hog(img): - gx = cv2.Sobel(img, cv2.CV_32F, 1, 0) - gy = cv2.Sobel(img, cv2.CV_32F, 0, 1) - mag, ang = cv2.cartToPolar(gx, gy) - - # quantizing binvalues in (0...16) - bins = np.int32(bin_n*ang/(2*np.pi)) - - # Divide to 4 sub-squares - bin_cells = bins[:10,:10], bins[10:,:10], bins[:10,10:], bins[10:,10:] - mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:] - hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)] - hist = np.hstack(hists) - return hist - - -Finally, as in the previous case, we start by splitting our big dataset into individual cells. For every digit, 250 cells are reserved for training data and remaining 250 data is reserved for testing. Full code is given below: -:: - - import cv2 - import numpy as np - - SZ=20 - bin_n = 16 # Number of bins - - svm_params = dict( kernel_type = cv2.SVM_LINEAR, - svm_type = cv2.SVM_C_SVC, - C=2.67, gamma=5.383 ) - - affine_flags = cv2.WARP_INVERSE_MAP|cv2.INTER_LINEAR - - def deskew(img): - m = cv2.moments(img) - if abs(m['mu02']) < 1e-2: - return img.copy() - skew = m['mu11']/m['mu02'] - M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]]) - img = cv2.warpAffine(img,M,(SZ, SZ),flags=affine_flags) - return img - - def hog(img): - gx = cv2.Sobel(img, cv2.CV_32F, 1, 0) - gy = cv2.Sobel(img, cv2.CV_32F, 0, 1) - mag, ang = cv2.cartToPolar(gx, gy) - bins = np.int32(bin_n*ang/(2*np.pi)) # quantizing binvalues in (0...16) - bin_cells = bins[:10,:10], bins[10:,:10], bins[:10,10:], bins[10:,10:] - mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:] - hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)] - hist = np.hstack(hists) # hist is a 64 bit vector - return hist - - img = cv2.imread('digits.png',0) - - cells = [np.hsplit(row,100) for row in np.vsplit(img,50)] - - # First half is trainData, remaining is testData - train_cells = [ i[:50] for i in cells ] - test_cells = [ i[50:] for i in cells] - - ###### Now training ######################## - - deskewed = [map(deskew,row) for row in train_cells] - hogdata = [map(hog,row) for row in deskewed] - trainData = np.float32(hogdata).reshape(-1,64) - responses = np.float32(np.repeat(np.arange(10),250)[:,np.newaxis]) - - svm = cv2.SVM() - svm.train(trainData,responses, params=svm_params) - svm.save('svm_data.dat') - - ###### Now testing ######################## - - deskewed = [map(deskew,row) for row in test_cells] - hogdata = [map(hog,row) for row in deskewed] - testData = np.float32(hogdata).reshape(-1,bin_n*4) - result = svm.predict_all(testData) - - ####### Check Accuracy ######################## - mask = result==responses - correct = np.count_nonzero(mask) - print correct*100.0/result.size - -This particular technique gave me nearly 94% accuracy. You can try different values for various parameters of SVM to check if higher accuracy is possible. Or you can read technical papers on this area and try to implement them. - - -Additional Resources -===================== - -1. `Histograms of Oriented Gradients Video `_ - -Exercises -============== -1. OpenCV samples contain ``digits.py`` which applies a slight improvement of the above method to get improved result. It also contains the reference. Check it and understand it. diff --git a/doc/py_tutorials/py_ml/py_table_of_contents_ml/py_table_of_contents_ml.markdown b/doc/py_tutorials/py_ml/py_table_of_contents_ml.markdown similarity index 100% rename from doc/py_tutorials/py_ml/py_table_of_contents_ml/py_table_of_contents_ml.markdown rename to doc/py_tutorials/py_ml/py_table_of_contents_ml.markdown diff --git a/doc/py_tutorials/py_ml/py_table_of_contents_ml/py_table_of_contents_ml.rst b/doc/py_tutorials/py_ml/py_table_of_contents_ml/py_table_of_contents_ml.rst deleted file mode 100644 index c7b5552b73..0000000000 --- a/doc/py_tutorials/py_ml/py_table_of_contents_ml/py_table_of_contents_ml.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. _PY_Table-Of-Content-ML: - -Machine Learning -******************** - -* :ref:`KNN` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |ML_KNN| Learn to use kNN for classification - Plus learn about handwritten digit recognition using kNN - =========== =================================================================== - - .. |ML_KNN| image:: images/knnicon.png - :height: 90pt - :width: 90pt - - -* :ref:`SVM` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |ML_SVM| Understand concepts of SVM - =========== =================================================================== - - .. |ML_SVM| image:: images/svmicon.png - :height: 90pt - :width: 90pt - -* :ref:`KMeans_Clustering` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== =================================================================== - |ML_KM| Learn to use K-Means Clustering to group data to a number of clusters. - Plus learn to do color quantization using K-Means Clustering - =========== =================================================================== - - .. |ML_KM| image:: images/kmeansicon.jpg - :height: 90pt - :width: 90pt - - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_knn/py_knn_index - ../py_svm/py_svm_index - ../py_kmeans/py_kmeans_index diff --git a/doc/py_tutorials/py_objdetect/py_table_of_contents_objdetect/images/face_icon.jpg b/doc/py_tutorials/py_objdetect/images/face_icon.jpg similarity index 100% rename from doc/py_tutorials/py_objdetect/py_table_of_contents_objdetect/images/face_icon.jpg rename to doc/py_tutorials/py_objdetect/images/face_icon.jpg diff --git a/doc/py_tutorials/py_objdetect/py_face_detection/py_face_detection.rst b/doc/py_tutorials/py_objdetect/py_face_detection/py_face_detection.rst deleted file mode 100644 index e1716eb4ce..0000000000 --- a/doc/py_tutorials/py_objdetect/py_face_detection/py_face_detection.rst +++ /dev/null @@ -1,104 +0,0 @@ -.. _face_detection: - - -Face Detection using Haar Cascades -*************************************** - -Goal -======== - -In this session, - - * We will see the basics of face detection using Haar Feature-based Cascade Classifiers - * We will extend the same for eye detection etc. - - -Basics -========= - -Object Detection using Haar feature-based cascade classifiers is an effective object detection method proposed by Paul Viola and Michael Jones in their paper, "Rapid Object Detection using a Boosted Cascade of Simple Features" in 2001. It is a machine learning based approach where a cascade function is trained from a lot of positive and negative images. It is then used to detect objects in other images. - -Here we will work with face detection. Initially, the algorithm needs a lot of positive images (images of faces) and negative images (images without faces) to train the classifier. Then we need to extract features from it. For this, haar features shown in below image are used. They are just like our convolutional kernel. Each feature is a single value obtained by subtracting sum of pixels under white rectangle from sum of pixels under black rectangle. - - .. image:: images/haar_features.jpg - :alt: Haar Features - :align: center - - -Now all possible sizes and locations of each kernel is used to calculate plenty of features. (Just imagine how much computation it needs? Even a 24x24 window results over 160000 features). For each feature calculation, we need to find sum of pixels under white and black rectangles. To solve this, they introduced the integral images. It simplifies calculation of sum of pixels, how large may be the number of pixels, to an operation involving just four pixels. Nice, isn't it? It makes things super-fast. - -But among all these features we calculated, most of them are irrelevant. For example, consider the image below. Top row shows two good features. The first feature selected seems to focus on the property that the region of the eyes is often darker than the region of the nose and cheeks. The second feature selected relies on the property that the eyes are darker than the bridge of the nose. But the same windows applying on cheeks or any other place is irrelevant. So how do we select the best features out of 160000+ features? It is achieved by **Adaboost**. - - .. image:: images/haar.png - :alt: Face Detection - :align: center - -For this, we apply each and every feature on all the training images. For each feature, it finds the best threshold which will classify the faces to positive and negative. But obviously, there will be errors or misclassifications. We select the features with minimum error rate, which means they are the features that best classifies the face and non-face images. (The process is not as simple as this. Each image is given an equal weight in the beginning. After each classification, weights of misclassified images are increased. Then again same process is done. New error rates are calculated. Also new weights. The process is continued until required accuracy or error rate is achieved or required number of features are found). - -Final classifier is a weighted sum of these weak classifiers. It is called weak because it alone can't classify the image, but together with others forms a strong classifier. The paper says even 200 features provide detection with 95% accuracy. Their final setup had around 6000 features. (Imagine a reduction from 160000+ features to 6000 features. That is a big gain). - -So now you take an image. Take each 24x24 window. Apply 6000 features to it. Check if it is face or not. Wow.. Wow.. Isn't it a little inefficient and time consuming? Yes, it is. Authors have a good solution for that. - -In an image, most of the image region is non-face region. So it is a better idea to have a simple method to check if a window is not a face region. If it is not, discard it in a single shot. Don't process it again. Instead focus on region where there can be a face. This way, we can find more time to check a possible face region. - -For this they introduced the concept of **Cascade of Classifiers**. Instead of applying all the 6000 features on a window, group the features into different stages of classifiers and apply one-by-one. (Normally first few stages will contain very less number of features). If a window fails the first stage, discard it. We don't consider remaining features on it. If it passes, apply the second stage of features and continue the process. The window which passes all stages is a face region. How is the plan !!! - -Authors' detector had 6000+ features with 38 stages with 1, 10, 25, 25 and 50 features in first five stages. (Two features in the above image is actually obtained as the best two features from Adaboost). According to authors, on an average, 10 features out of 6000+ are evaluated per sub-window. - -So this is a simple intuitive explanation of how Viola-Jones face detection works. Read paper for more details or check out the references in Additional Resources section. - - -Haar-cascade Detection in OpenCV -=================================== - -OpenCV comes with a trainer as well as detector. If you want to train your own classifier for any object like car, planes etc. you can use OpenCV to create one. Its full details are given here: `Cascade Classifier Training. `_ - -Here we will deal with detection. OpenCV already contains many pre-trained classifiers for face, eyes, smile etc. Those XML files are stored in ``opencv/data/haarcascades/`` folder. Let's create face and eye detector with OpenCV. - -First we need to load the required XML classifiers. Then load our input image (or video) in grayscale mode. -:: - - import numpy as np - import cv2 - - face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') - eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml') - - img = cv2.imread('sachin.jpg') - gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - - -Now we find the faces in the image. If faces are found, it returns the positions of detected faces as Rect(x,y,w,h). Once we get these locations, we can create a ROI for the face and apply eye detection on this ROI (since eyes are always on the face !!! ). -:: - - faces = face_cascade.detectMultiScale(gray, 1.3, 5) - for (x,y,w,h) in faces: - cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) - roi_gray = gray[y:y+h, x:x+w] - roi_color = img[y:y+h, x:x+w] - eyes = eye_cascade.detectMultiScale(roi_gray) - for (ex,ey,ew,eh) in eyes: - cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2) - - cv2.imshow('img',img) - cv2.waitKey(0) - cv2.destroyAllWindows() - - -Result looks like below: - - .. image:: images/face.jpg - :alt: Face Detection - :align: center - - -Additional Resources -======================= - -#. Video Lecture on `Face Detection and Tracking `_ - -#. An interesting interview regarding Face Detection by `Adam Harvey `_ - - -Exercises -=========== diff --git a/doc/py_tutorials/py_objdetect/py_table_of_contents_objdetect/py_table_of_contents_objdetect.markdown b/doc/py_tutorials/py_objdetect/py_table_of_contents_objdetect.markdown similarity index 100% rename from doc/py_tutorials/py_objdetect/py_table_of_contents_objdetect/py_table_of_contents_objdetect.markdown rename to doc/py_tutorials/py_objdetect/py_table_of_contents_objdetect.markdown diff --git a/doc/py_tutorials/py_objdetect/py_table_of_contents_objdetect/py_table_of_contents_objdetect.rst b/doc/py_tutorials/py_objdetect/py_table_of_contents_objdetect/py_table_of_contents_objdetect.rst deleted file mode 100644 index a5d8a70b76..0000000000 --- a/doc/py_tutorials/py_objdetect/py_table_of_contents_objdetect/py_table_of_contents_objdetect.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. _PY_Table-Of-Content-Objdetection: - - -Object Detection --------------------------------- - - - -* :ref:`face_detection` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |objdet_1| Face detection using haar-cascades - - =========== ====================================================== - - .. |objdet_1| image:: images/face_icon.jpg - :height: 90pt - :width: 90pt - - - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_face_detection/py_face_detection diff --git a/doc/py_tutorials/py_photo/py_table_of_contents_photo/images/inpainticon.jpg b/doc/py_tutorials/py_photo/images/inpainticon.jpg similarity index 100% rename from doc/py_tutorials/py_photo/py_table_of_contents_photo/images/inpainticon.jpg rename to doc/py_tutorials/py_photo/images/inpainticon.jpg diff --git a/doc/py_tutorials/py_photo/py_table_of_contents_photo/images/nlm_icon.jpg b/doc/py_tutorials/py_photo/images/nlm_icon.jpg similarity index 100% rename from doc/py_tutorials/py_photo/py_table_of_contents_photo/images/nlm_icon.jpg rename to doc/py_tutorials/py_photo/images/nlm_icon.jpg diff --git a/doc/py_tutorials/py_photo/py_inpainting/py_inpainting.rst b/doc/py_tutorials/py_photo/py_inpainting/py_inpainting.rst deleted file mode 100644 index 9c92e7cb0f..0000000000 --- a/doc/py_tutorials/py_photo/py_inpainting/py_inpainting.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. _inpainting: - - -Image Inpainting -********************** - -Goal -====== - -In this chapter, - * We will learn how to remove small noises, strokes etc in old photographs by a method called inpainting - * We will see inpainting functionalities in OpenCV. - - -Basics -=========== - -Most of you will have some old degraded photos at your home with some black spots, some strokes etc on it. Have you ever thought of restoring it back? We can't simply erase them in a paint tool because it is will simply replace black structures with white structures which is of no use. In these cases, a technique called image inpainting is used. The basic idea is simple: Replace those bad marks with its neighbouring pixels so that it looks like the neigbourhood. Consider the image shown below (taken from `Wikipedia `_): - - .. image:: images/inpaint_basics.jpg - :alt: Inpainting example - :align: center - -Several algorithms were designed for this purpose and OpenCV provides two of them. Both can be accessed by the same function, **cv2.inpaint()** - -First algorithm is based on the paper **"An Image Inpainting Technique Based on the Fast Marching Method"** by Alexandru Telea in 2004. It is based on Fast Marching Method. Consider a region in the image to be inpainted. Algorithm starts from the boundary of this region and goes inside the region gradually filling everything in the boundary first. It takes a small neighbourhood around the pixel on the neigbourhood to be inpainted. This pixel is replaced by normalized weighted sum of all the known pixels in the neigbourhood. Selection of the weights is an important matter. More weightage is given to those pixels lying near to the point, near to the normal of the boundary and those lying on the boundary contours. Once a pixel is inpainted, it moves to next nearest pixel using Fast Marching Method. FMM ensures those pixels near the known pixels are inpainted first, so that it just works like a manual heuristic operation. This algorithm is enabled by using the flag, ``cv2.INPAINT_TELEA``. - -Second algorithm is based on the paper **"Navier-Stokes, Fluid Dynamics, and Image and Video Inpainting"** by Bertalmio, Marcelo, Andrea L. Bertozzi, and Guillermo Sapiro in 2001. This algorithm is based on fluid dynamics and utilizes partial differential equations. Basic principle is heurisitic. It first travels along the edges from known regions to unknown regions (because edges are meant to be continuous). It continues isophotes (lines joining points with same intensity, just like contours joins points with same elevation) while matching gradient vectors at the boundary of the inpainting region. For this, some methods from fluid dynamics are used. Once they are obtained, color is filled to reduce minimum variance in that area. This algorithm is enabled by using the flag, ``cv2.INPAINT_NS``. - - -Code -=========== - -We need to create a mask of same size as that of input image, where non-zero pixels corresponds to the area which is to be inpainted. Everything else is simple. My image is degraded with some black strokes (I added manually). I created a corresponding strokes with Paint tool. -:: - - import numpy as np - import cv2 - - img = cv2.imread('messi_2.jpg') - mask = cv2.imread('mask2.png',0) - - dst = cv2.inpaint(img,mask,3,cv2.INPAINT_TELEA) - - cv2.imshow('dst',dst) - cv2.waitKey(0) - cv2.destroyAllWindows() - - -See the result below. First image shows degraded input. Second image is the mask. Third image is the result of first algorithm and last image is the result of second algorithm. - - .. image:: images/inpaint_result.jpg - :alt: Inpainting result - :align: center - - -Additional Resources -========================= - -#. Bertalmio, Marcelo, Andrea L. Bertozzi, and Guillermo Sapiro. "Navier-stokes, fluid dynamics, and image and video inpainting." In Computer Vision and Pattern Recognition, 2001. CVPR 2001. Proceedings of the 2001 IEEE Computer Society Conference on, vol. 1, pp. I-355. IEEE, 2001. - -#. Telea, Alexandru. "An image inpainting technique based on the fast marching method." Journal of graphics tools 9.1 (2004): 23-34. - - -Exercises -================ - -#. OpenCV comes with an interactive sample on inpainting, ``samples/python2/inpaint.py``, try it. - -#. A few months ago, I watched a video on `Content-Aware Fill `_, an advanced inpainting technique used in Adobe Photoshop. On further search, I was able to find that same technique is already there in GIMP with different name, "Resynthesizer" (You need to install separate plugin). I am sure you will enjoy the technique. diff --git a/doc/py_tutorials/py_photo/py_non_local_means/py_non_local_means.rst b/doc/py_tutorials/py_photo/py_non_local_means/py_non_local_means.rst deleted file mode 100644 index ac63baa705..0000000000 --- a/doc/py_tutorials/py_photo/py_non_local_means/py_non_local_means.rst +++ /dev/null @@ -1,139 +0,0 @@ -.. _non_local_means: - - -Image Denoising -************************ - -Goal -========= - -In this chapter, - - * You will learn about Non-local Means Denoising algorithm to remove noise in the image. - * You will see different functions like **cv2.fastNlMeansDenoising()**, **cv2.fastNlMeansDenoisingColored()** etc. - - -Theory -========= - -In earlier chapters, we have seen many image smoothing techniques like Gaussian Blurring, Median Blurring etc and they were good to some extent in removing small quantities of noise. In those techniques, we took a small neighbourhood around a pixel and did some operations like gaussian weighted average, median of the values etc to replace the central element. In short, noise removal at a pixel was local to its neighbourhood. - -There is a property of noise. Noise is generally considered to be a random variable with zero mean. Consider a noisy pixel, :math:`p = p_0 + n` where :math:`p_0` is the true value of pixel and :math:`n` is the noise in that pixel. You can take large number of same pixels (say :math:`N`) from different images and computes their average. Ideally, you should get :math:`p = p_0` since mean of noise is zero. - -You can verify it yourself by a simple setup. Hold a static camera to a certain location for a couple of seconds. This will give you plenty of frames, or a lot of images of the same scene. Then write a piece of code to find the average of all the frames in the video (This should be too simple for you now ). Compare the final result and first frame. You can see reduction in noise. Unfortunately this simple method is not robust to camera and scene motions. Also often there is only one noisy image available. - -So idea is simple, we need a set of similar images to average out the noise. Consider a small window (say 5x5 window) in the image. Chance is large that the same patch may be somewhere else in the image. Sometimes in a small neigbourhood around it. What about using these similar patches together and find their average? For that particular window, that is fine. See an example image below: - - .. image:: images/nlm_patch.jpg - :alt: Similar patches - :align: center - -The blue patches in the image looks the similar. Green patches looks similar. So we take a pixel, take small window around it, search for similar windows in the image, average all the windows and replace the pixel with the result we got. This method is Non-Local Means Denoising. It takes more time compared to blurring techniques we saw earlier, but its result is very good. More details and online demo can be found at first link in additional resources. - -For color images, image is converted to CIELAB colorspace and then it separately denoise L and AB components. - - -Image Denoising in OpenCV -=================================== - -OpenCV provides four variations of this technique. - -#. **cv2.fastNlMeansDenoising()** - works with a single grayscale images -#. **cv2.fastNlMeansDenoisingColored()** - works with a color image. -#. **cv2.fastNlMeansDenoisingMulti()** - works with image sequence captured in short period of time (grayscale images) -#. **cv2.fastNlMeansDenoisingColoredMulti()** - same as above, but for color images. - -Common arguments are: - * h : parameter deciding filter strength. Higher h value removes noise better, but removes details of image also. (10 is ok) - * hForColorComponents : same as h, but for color images only. (normally same as h) - * templateWindowSize : should be odd. (recommended 7) - * searchWindowSize : should be odd. (recommended 21) - -Please visit first link in additional resources for more details on these parameters. - -We will demonstrate 2 and 3 here. Rest is left for you. - - -1. cv2.fastNlMeansDenoisingColored() ------------------------------------------- - -As mentioned above it is used to remove noise from color images. (Noise is expected to be gaussian). See the example below: -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - img = cv2.imread('die.png') - - dst = cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21) - - plt.subplot(121),plt.imshow(img) - plt.subplot(122),plt.imshow(dst) - plt.show() - - -Below is a zoomed version of result. My input image has a gaussian noise of :math:`\sigma = 25`. See the result: - - .. image:: images/nlm_result1.jpg - :alt: Result of denoising - :align: center - - -2. cv2.fastNlMeansDenoisingMulti() ------------------------------------------- -Now we will apply the same method to a video. The first argument is the list of noisy frames. Second argument `imgToDenoiseIndex` specifies which frame we need to denoise, for that we pass the index of frame in our input list. Third is the `temporalWindowSize` which specifies the number of nearby frames to be used for denoising. It should be odd. In that case, a total of `temporalWindowSize` frames are used where central frame is the frame to be denoised. For example, you passed a list of 5 frames as input. Let `imgToDenoiseIndex = 2` and `temporalWindowSize = 3`. Then frame-1, frame-2 and frame-3 are used to denoise frame-2. Let's see an example. -:: - - import numpy as np - import cv2 - from matplotlib import pyplot as plt - - cap = cv2.VideoCapture('vtest.avi') - - # create a list of first 5 frames - img = [cap.read()[1] for i in xrange(5)] - - # convert all to grayscale - gray = [cv2.cvtColor(i, cv2.COLOR_BGR2GRAY) for i in img] - - # convert all to float64 - gray = [np.float64(i) for i in gray] - - # create a noise of variance 25 - noise = np.random.randn(*gray[1].shape)*10 - - # Add this noise to images - noisy = [i+noise for i in gray] - - # Convert back to uint8 - noisy = [np.uint8(np.clip(i,0,255)) for i in noisy] - - # Denoise 3rd frame considering all the 5 frames - dst = cv2.fastNlMeansDenoisingMulti(noisy, 2, 5, None, 4, 7, 35) - - plt.subplot(131),plt.imshow(gray[2],'gray') - plt.subplot(132),plt.imshow(noisy[2],'gray') - plt.subplot(133),plt.imshow(dst,'gray') - plt.show() - - -Below image shows a zoomed version of the result we got: - - .. image:: images/nlm_multi.jpg - :alt: Denoising a frame - :align: center - - -It takes considerable amount of time for computation. In the result, first image is the original frame, second is the noisy one, third is the denoised image. - - -Additional Resources -======================== - -#. http://www.ipol.im/pub/art/2011/bcm_nlm/ (It has the details, online demo etc. Highly recommended to visit. Our test image is generated from this link) - -#. `Online course at coursera `_ (First image taken from here) - -Exercises -============ diff --git a/doc/py_tutorials/py_photo/py_table_of_contents_photo/py_table_of_contents_photo.markdown b/doc/py_tutorials/py_photo/py_table_of_contents_photo.markdown similarity index 100% rename from doc/py_tutorials/py_photo/py_table_of_contents_photo/py_table_of_contents_photo.markdown rename to doc/py_tutorials/py_photo/py_table_of_contents_photo.markdown diff --git a/doc/py_tutorials/py_photo/py_table_of_contents_photo/py_table_of_contents_photo.rst b/doc/py_tutorials/py_photo/py_table_of_contents_photo/py_table_of_contents_photo.rst deleted file mode 100644 index c08e946049..0000000000 --- a/doc/py_tutorials/py_photo/py_table_of_contents_photo/py_table_of_contents_photo.rst +++ /dev/null @@ -1,49 +0,0 @@ -.. _PY_Table-Of-Content-Photo: - - -Computational Photography --------------------------------- - -Here you will learn different OpenCV functionalities related to Computational Photography like image denoising etc. - - -* :ref:`non_local_means` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |photo_1| See a good technique to remove noises in images called Non-Local Means Denoising - - =========== ====================================================== - - .. |photo_1| image:: images/nlm_icon.jpg - :height: 90pt - :width: 90pt - - -* :ref:`inpainting` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |photo_2| Do you have a old degraded photo with many black spots and strokes on it? Take it. Let's try to restore them with a technique called image inpainting. - - =========== ====================================================== - - .. |photo_2| image:: images/inpainticon.jpg - :height: 90pt - :width: 90pt - - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_non_local_means/py_non_local_means - ../py_inpainting/py_inpainting diff --git a/doc/py_tutorials/py_setup/py_table_of_contents_setup/images/fedora_logo.jpg b/doc/py_tutorials/py_setup/images/fedora_logo.jpg similarity index 100% rename from doc/py_tutorials/py_setup/py_table_of_contents_setup/images/fedora_logo.jpg rename to doc/py_tutorials/py_setup/images/fedora_logo.jpg diff --git a/doc/py_tutorials/py_setup/py_table_of_contents_setup/images/opencv_logo.jpg b/doc/py_tutorials/py_setup/images/opencv_logo.jpg similarity index 100% rename from doc/py_tutorials/py_setup/py_table_of_contents_setup/images/opencv_logo.jpg rename to doc/py_tutorials/py_setup/images/opencv_logo.jpg diff --git a/doc/py_tutorials/py_setup/py_table_of_contents_setup/images/windows_logo.jpg b/doc/py_tutorials/py_setup/images/windows_logo.jpg similarity index 100% rename from doc/py_tutorials/py_setup/py_table_of_contents_setup/images/windows_logo.jpg rename to doc/py_tutorials/py_setup/images/windows_logo.jpg diff --git a/doc/py_tutorials/py_setup/py_intro/py_intro.rst b/doc/py_tutorials/py_setup/py_intro/py_intro.rst deleted file mode 100644 index 65b30c2e53..0000000000 --- a/doc/py_tutorials/py_setup/py_intro/py_intro.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. _Intro: - - -Introduction to OpenCV-Python Tutorials -******************************************* - -OpenCV -=============== - -OpenCV was started at Intel in 1999 by **Gary Bradsky**, and the first release came out in 2000. **Vadim Pisarevsky** joined Gary Bradsky to manage Intel's Russian software OpenCV team. In 2005, OpenCV was used on Stanley, the vehicle that won the 2005 DARPA Grand Challenge. Later, its active development continued under the support of Willow Garage with Gary Bradsky and Vadim Pisarevsky leading the project. OpenCV now supports a multitude of algorithms related to Computer Vision and Machine Learning and is expanding day by day. - -OpenCV supports a wide variety of programming languages such as C++, Python, Java, etc., and is available on different platforms including Windows, Linux, OS X, Android, and iOS. Interfaces for high-speed GPU operations based on CUDA and OpenCL are also under active development. - -OpenCV-Python is the Python API for OpenCV, combining the best qualities of the OpenCV C++ API and the Python language. - - -OpenCV-Python -=============== - -OpenCV-Python is a library of Python bindings designed to solve computer vision problems. - -Python is a general purpose programming language started by **Guido van Rossum** that became very popular very quickly, mainly because of its simplicity and code readability. It enables the programmer to express ideas in fewer lines of code without reducing readability. - -Compared to languages like C/C++, Python is slower. That said, Python can be easily extended with C/C++, which allows us to write computationally intensive code in C/C++ and create Python wrappers that can be used as Python modules. This gives us two advantages: first, the code is as fast as the original C/C++ code (since it is the actual C++ code working in background) and second, it easier to code in Python than C/C++. OpenCV-Python is a Python wrapper for the original OpenCV C++ implementation. - -OpenCV-Python makes use of **Numpy**, which is a highly optimized library for numerical operations with a MATLAB-style syntax. All the OpenCV array structures are converted to and from Numpy arrays. This also makes it easier to integrate with other libraries that use Numpy such as SciPy and Matplotlib. - - -OpenCV-Python Tutorials -============================= - -OpenCV introduces a new set of tutorials which will guide you through various functions available in OpenCV-Python. **This guide is mainly focused on OpenCV 3.x version** (although most of the tutorials will also work with OpenCV 2.x). - -Prior knowledge of Python and Numpy is recommended as they won't be covered in this guide. **Proficiency with Numpy is a must in order to write optimized code using OpenCV-Python.** - -This tutorial was originally started by *Abid Rahman K.* as part of the Google Summer of Code 2013 program under the guidance of *Alexander Mordvintsev*. - - -OpenCV Needs You !!! -========================== - -Since OpenCV is an open source initiative, all are welcome to make contributions to the library, documentation, and tutorials. If you find any mistake in this tutorial (from a small spelling mistake to an egregious error in code or concept), feel free to correct it by cloning OpenCV in `GitHub `_ and submitting a pull request. OpenCV developers will check your pull request, give you important feedback and (once it passes the approval of the reviewer) it will be merged into OpenCV. You will then become an open source contributor :-) - -As new modules are added to OpenCV-Python, this tutorial will have to be expanded. If you are familiar with a particular algorithm and can write up a tutorial including basic theory of the algorithm and code showing example usage, please do so. - -Remember, we **together** can make this project a great success !!! - - -Contributors -================= - -Below is the list of contributors who submitted tutorials to OpenCV-Python. - -1. Alexander Mordvintsev (GSoC-2013 mentor) -2. Abid Rahman K. (GSoC-2013 intern) - - -Additional Resources -======================= - -1. A Quick guide to Python - `A Byte of Python `_ -2. `Basic Numpy Tutorials `_ -3. `Numpy Examples List `_ -4. `OpenCV Documentation `_ -5. `OpenCV Forum `_ diff --git a/doc/py_tutorials/py_setup/py_setup_in_fedora/py_setup_in_fedora.rst b/doc/py_tutorials/py_setup/py_setup_in_fedora/py_setup_in_fedora.rst deleted file mode 100644 index 581b1ed3d1..0000000000 --- a/doc/py_tutorials/py_setup/py_setup_in_fedora/py_setup_in_fedora.rst +++ /dev/null @@ -1,270 +0,0 @@ -.. _Install-OpenCV-Python-in-Fedora: - -Install OpenCV-Python in Fedora -********************************* - -Goals -====== - -In this tutorial - * We will learn to setup OpenCV-Python in your Fedora system. Below steps are tested for Fedora 18 (64-bit) and Fedora 19 (32-bit). - -Introduction -================== - -OpenCV-Python can be installed in Fedora in two ways, 1) Install from pre-built binaries available in fedora repositories, 2) Compile from the source. In this section, we will see both. - -Another important thing is the additional libraries required. OpenCV-Python requires only **Numpy** (in addition to other dependencies, which we will see later). But in this tutorials, we also use **Matplotlib** for some easy and nice plotting purposes (which I feel much better compared to OpenCV). Matplotlib is optional, but highly recommended. Similarly we will also see **IPython**, an Interactive Python Terminal, which is also highly recommended. - - -Installing OpenCV-Python from Pre-built Binaries -=================================================== - -Install all packages with following command in terminal as root. - - .. code-block:: bash - - $ yum install numpy opencv* - -Open Python IDLE (or IPython) and type following codes in Python terminal. - - .. code-block:: python - - >>> import cv2 - >>> print cv2.__version__ - -If the results are printed out without any errors, congratulations !!! You have installed OpenCV-Python successfully. - -It is quite easy. But there is a problem with this. Yum repositories may not contain the latest version of OpenCV always. For example, at the time of writing this tutorial, yum repository contains 2.4.5 while latest OpenCV version is 2.4.6. With respect to Python API, latest version will always contain much better support. Also, there may be chance of problems with camera support, video playback etc depending upon the drivers, ffmpeg, gstreamer packages present etc. - -So my personnel preference is next method, i.e. compiling from source. Also at some point of time, if you want to contribute to OpenCV, you will need this. - - -Installing OpenCV from source -=============================== - -Compiling from source may seem a little complicated at first, but once you succeeded in it, there is nothing complicated. - -First we will install some dependencies. Some are compulsory, some are optional. Optional dependencies, you can leave if you don't want. - - -Compulsory Dependencies ---------------------------- - - -We need **CMake** to configure the installation, **GCC** for compilation, **Python-devel** and **Numpy** for creating Python extensions etc. - - .. code-block:: bash - - yum install cmake - yum install python-devel numpy - yum install gcc gcc-c++ - - -Next we need **GTK** support for GUI features, Camera support (libdc1394, libv4l), Media Support (ffmpeg, gstreamer) etc. - - .. code-block:: bash - - yum install gtk2-devel - yum install libdc1394-devel - yum install libv4l-devel - yum install ffmpeg-devel - yum install gstreamer-plugins-base-devel - - -Optional Dependencies --------------------------- - -Above dependencies are sufficient to install OpenCV in your fedora machine. But depending upon your requirements, you may need some extra dependencies. A list of such optional dependencies are given below. You can either leave it or install it, your call :) - -OpenCV comes with supporting files for image formats like PNG, JPEG, JPEG2000, TIFF, WebP etc. But it may be a little old. If you want to get latest libraries, you can install development files for these formats. - - .. code-block:: bash - - yum install libpng-devel - yum install libjpeg-turbo-devel - yum install jasper-devel - yum install openexr-devel - yum install libtiff-devel - yum install libwebp-devel - - -Several OpenCV functions are parallelized with **Intel's Threading Building Blocks** (TBB). But if you want to enable it, you need to install TBB first. ( Also while configuring installation with CMake, don't forget to pass ``-D WITH_TBB=ON``. More details below.) - - .. code-block:: bash - - yum install tbb-devel - -OpenCV uses another library **Eigen** for optimized mathematical operations. So if you have Eigen installed in your system, you can exploit it. ( Also while configuring installation with CMake, don't forget to pass ``-D WITH_EIGEN=ON``. More details below.) - - .. code-block:: bash - - yum install eigen3-devel - -If you want to build **documentation** ( *Yes, you can create offline version of OpenCV's complete official documentation in your system in HTML with full search facility so that you need not access internet always if any question, and it is quite FAST!!!* ), you need to install **Sphinx** (a documentation generation tool) and **pdflatex** (if you want to create a PDF version of it). ( Also while configuring installation with CMake, don't forget to pass ``-D BUILD_DOCS=ON``. More details below.) - - .. code-block:: bash - - yum install python-sphinx - yum install texlive - - -Downloading OpenCV ------------------------ - -Next we have to download OpenCV. You can download the latest release of OpenCV from `sourceforge site `_. Then extract the folder. - -Or you can download latest source from OpenCV's github repo. (If you want to contribute to OpenCV, choose this. It always keeps your OpenCV up-to-date). For that, you need to install **Git** first. - - .. code-block:: bash - - yum install git - git clone https://github.com/Itseez/opencv.git - -It will create a folder ``OpenCV`` in home directory (or the directory you specify). The cloning may take some time depending upon your internet connection. - -Now open a terminal window and navigate to the downloaded OpenCV folder. Create a new ``build`` folder and navigate to it. - - .. code-block:: bash - - mkdir build - cd build - - -Configuring and Installing ----------------------------- - -Now we have installed all the required dependencies, let's install OpenCV. Installation has to be configured with CMake. It specifies which modules are to be installed, installation path, which additional libraries to be used, whether documentation and examples to be compiled etc. Below command is normally used for configuration (executed from ``build`` folder). - - .. code-block:: bash - - cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local .. - -It specifies that build type is "Release Mode" and installation path is ``/usr/local``. Observe the ``-D`` before each option and ``..`` at the end. In short, this is the format: - - .. code-block:: bash - - cmake [-D ] [-D ] .. - -You can specify as many flags you want, but each flag should be preceded by ``-D``. - -So in this tutorial, we are installing OpenCV with TBB and Eigen support. We also build the documentation, but we exclude Performance tests and building samples. We also disable GPU related modules (since we use OpenCV-Python, we don't need GPU related modules. It saves us some time). - -*(All the below commands can be done in a single cmake statement, but it is split here for better understanding.)* - -* Enable TBB and Eigen support: - - .. code-block:: bash - - cmake -D WITH_TBB=ON -D WITH_EIGEN=ON .. - -* Enable documentation and disable tests and samples - - .. code-block:: bash - - cmake -D BUILD_DOCS=ON -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D BUILD_EXAMPLES=OFF .. - -* Disable all GPU related modules. - - .. code-block:: bash - - cmake -D WITH_OPENCL=OFF -D WITH_CUDA=OFF -D BUILD_opencv_gpu=OFF -D BUILD_opencv_gpuarithm=OFF -D BUILD_opencv_gpubgsegm=OFF -D BUILD_opencv_gpucodec=OFF -D BUILD_opencv_gpufeatures2d=OFF -D BUILD_opencv_gpufilters=OFF -D BUILD_opencv_gpuimgproc=OFF -D BUILD_opencv_gpulegacy=OFF -D BUILD_opencv_gpuoptflow=OFF -D BUILD_opencv_gpustereo=OFF -D BUILD_opencv_gpuwarping=OFF .. - -* Set installation path and build type - - .. code-block:: bash - - cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local .. - - -Each time you enter cmake statement, it prints out the resulting configuration setup. In the final setup you got, make sure that following fields are filled (below is the some important parts of configuration I got). These fields should be filled appropriately in your system also. Otherwise some problem has happened. So check if you have correctly performed above steps. - - .. code-block:: bash - - -- GUI: - -- GTK+ 2.x: YES (ver 2.24.19) - -- GThread : YES (ver 2.36.3) - - -- Video I/O: - -- DC1394 2.x: YES (ver 2.2.0) - -- FFMPEG: YES - -- codec: YES (ver 54.92.100) - -- format: YES (ver 54.63.104) - -- util: YES (ver 52.18.100) - -- swscale: YES (ver 2.2.100) - -- gentoo-style: YES - -- GStreamer: - -- base: YES (ver 0.10.36) - -- video: YES (ver 0.10.36) - -- app: YES (ver 0.10.36) - -- riff: YES (ver 0.10.36) - -- pbutils: YES (ver 0.10.36) - - -- V4L/V4L2: Using libv4l (ver 1.0.0) - - -- Other third-party libraries: - -- Use Eigen: YES (ver 3.1.4) - -- Use TBB: YES (ver 4.0 interface 6004) - - -- Python: - -- Interpreter: /usr/bin/python2 (ver 2.7.5) - -- Libraries: /lib/libpython2.7.so (ver 2.7.5) - -- numpy: /usr/lib/python2.7/site-packages/numpy/core/include (ver 1.7.1) - -- packages path: lib/python2.7/site-packages - - -- Documentation: - -- Build Documentation: YES - -- Sphinx: /usr/bin/sphinx-build (ver 1.1.3) - -- PdfLaTeX compiler: /usr/bin/pdflatex - -- - -- Tests and samples: - -- Tests: NO - -- Performance tests: NO - -- C/C++ Examples: NO - - -Many other flags and settings are there. It is left for you for further exploration. - -Now you build the files using ``make`` command and install it using ``make install`` command. ``make install`` should be executed as root. - - .. code-block:: bash - - make - su - make install - -Installation is over. All files are installed in ``/usr/local/`` folder. But to use it, your Python should be able to find OpenCV module. You have two options for that. - -1. **Move the module to any folder in Python Path** : Python path can be found out by entering ``import sys;print sys.path`` in Python terminal. It will print out many locations. Move ``/usr/local/lib/python2.7/site-packages/cv2.so`` to any of this folder. For example, - - .. code-block:: bash - - su mv /usr/local/lib/python2.7/site-packages/cv2.so /usr/lib/python2.7/site-packages - -But you will have to do this every time you install OpenCV. - -2. **Add ``/usr/local/lib/python2.7/site-packages`` to the PYTHON_PATH**: It is to be done only once. Just open ``~/.bashrc`` and add following line to it, then log out and come back. - - .. code-block:: bash - - export PYTHONPATH=$PYTHONPATH:/usr/local/lib/python2.7/site-packages - -Thus OpenCV installation is finished. Open a terminal and try ``import cv2``. - -To build the documentation, just enter following commands: - - .. code-block:: bash - - make docs - make html_docs - -Then open ``opencv/build/doc/_html/index.html`` and bookmark it in the browser. - - -Additional Resources -======================== - -Exercises -=============== - -1. Compile OpenCV from source in your Fedora machine. diff --git a/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.rst b/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.rst deleted file mode 100644 index 122925565a..0000000000 --- a/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.rst +++ /dev/null @@ -1,155 +0,0 @@ -.. _Install-OpenCV-Python-in-Windows: - -Install OpenCV-Python in Windows -********************************* - -Goals -====== - -In this tutorial - * We will learn to setup OpenCV-Python in your Windows system. - -*Below steps are tested in a Windows 7-64 bit machine with Visual Studio 2010 and Visual Studio 2012. The screenshots shows VS2012.* - -Installing OpenCV from prebuilt binaries -========================================= - -1. Below Python packages are to be downloaded and installed to their default locations. - - 1.1. `Python-2.7.x `_. - - 1.2. `Numpy `_. - - 1.3. `Matplotlib `_ (*Matplotlib is optional, but recommended since we use it a lot in our tutorials*). - -2. Install all packages into their default locations. Python will be installed to **C:/Python27/**. - -3. After installation, open Python IDLE. Enter ``import numpy`` and make sure Numpy is working fine. - -4. Download latest OpenCV release from `sourceforge site `_ and double-click to extract it. - -7. Goto **opencv/build/python/2.7** folder. - -8. Copy **cv2.pyd** to **C:/Python27/lib/site-packages**. - -9. Open Python IDLE and type following codes in Python terminal. - - >>> import cv2 - >>> print cv2.__version__ - -If the results are printed out without any errors, congratulations !!! You have installed OpenCV-Python successfully. - - -Building OpenCV from source -=============================== -1. Download and install Visual Studio and CMake. - - 1.1. `Visual Studio 2012 `_ - - 1.2. `CMake `_ - -2. Download and install necessary Python packages to their default locations - - 2.1. `Python 2.7.x `_ - - 2.2. `Numpy `_ - - 2.3. `Matplotlib `_ (*Matplotlib is optional, but recommended since we use it a lot in our tutorials.*) - -.. note:: In this case, we are using 32-bit binaries of Python packages. But if you want to use OpenCV for x64, 64-bit binaries of Python packages are to be installed. Problem is that, there is no official 64-bit binaries of Numpy. You have to build it on your own. For that, you have to use the same compiler used to build Python. When you start Python IDLE, it shows the compiler details. You can get more `information here `_. So your system must have the same Visual Studio version and build Numpy from source. - -.. note:: Another method to have 64-bit Python packages is to use ready-made Python distributions from third-parties like `Anaconda `_, `Enthought `_ etc. It will be bigger in size, but will have everything you need. Everything in a single shell. You can also download 32-bit versions also. - -3. Make sure Python and Numpy are working fine. - -4. Download OpenCV source. It can be from `Sourceforge `_ (for official release version) or from `Github `_ (for latest source). - -5. Extract it to a folder, ``opencv`` and create a new folder ``build`` in it. - -6. Open CMake-gui (*Start > All Programs > CMake-gui*) - -7. Fill the fields as follows (see the image below): - - 7.1. Click on **Browse Source...** and locate the ``opencv`` folder. - - 7.2. Click on **Browse Build...** and locate the ``build`` folder we created. - - 7.3. Click on **Configure**. - - .. image:: images/Capture1.jpg - :alt: capture1 - :align: center - - - 7.4. It will open a new window to select the compiler. Choose appropriate compiler (here, Visual Studio 11) and click **Finish**. - - .. image:: images/Capture2.png - :alt: capture2 - :align: center - - - 7.5. Wait until analysis is finished. - -8. You will see all the fields are marked in red. Click on the **WITH** field to expand it. It decides what extra features you need. So mark appropriate fields. See the below image: - - .. image:: images/Capture3.png - :alt: capture3 - :align: center - - -9. Now click on **BUILD** field to expand it. First few fields configure the build method. See the below image: - - .. image:: images/Capture5.png - :alt: capture5 - :align: center - - -10. Remaining fields specify what modules are to be built. Since GPU modules are not yet supported by OpenCV-Python, you can completely avoid it to save time (But if you work with them, keep it there). See the image below: - - .. image:: images/Capture6.png - :alt: capture6 - :align: center - - -11. Now click on **ENABLE** field to expand it. Make sure **ENABLE_SOLUTION_FOLDERS** is unchecked (Solution folders are not supported by Visual Studio Express edition). See the image below: - - .. image:: images/Capture7.png - :alt: capture7 - :align: center - - -12. Also make sure that in the **PYTHON** field, everything is filled. (Ignore PYTHON_DEBUG_LIBRARY). See image below: - - .. image:: images/Capture80.png - :alt: capture80 - :align: center - - -13. Finally click the **Generate** button. - -14. Now go to our **opencv/build** folder. There you will find **OpenCV.sln** file. Open it with Visual Studio. - -15. Check build mode as **Release** instead of **Debug**. - -16. In the solution explorer, right-click on the **Solution** (or **ALL_BUILD**) and build it. It will take some time to finish. - -17. Again, right-click on **INSTALL** and build it. Now OpenCV-Python will be installed. - - .. image:: images/Capture8.png - :alt: capture8 - :align: center - - -18. Open Python IDLE and enter ``import cv2``. If no error, it is installed correctly. - -.. note:: We have installed with no other support like TBB, Eigen, Qt, Documentation etc. It would be difficult to explain it here. A more detailed video will be added soon or you can just hack around. - - -Additional Resources -========================== - - -Exercises -============ - -1. If you have a windows machine, compile the OpenCV from source. Do all kinds of hacks. If you meet any problem, visit OpenCV forum and explain your problem. diff --git a/doc/py_tutorials/py_setup/py_table_of_contents_setup/py_table_of_contents_setup.markdown b/doc/py_tutorials/py_setup/py_table_of_contents_setup.markdown similarity index 100% rename from doc/py_tutorials/py_setup/py_table_of_contents_setup/py_table_of_contents_setup.markdown rename to doc/py_tutorials/py_setup/py_table_of_contents_setup.markdown diff --git a/doc/py_tutorials/py_setup/py_table_of_contents_setup/py_table_of_contents_setup.rst b/doc/py_tutorials/py_setup/py_table_of_contents_setup/py_table_of_contents_setup.rst deleted file mode 100644 index a89771a17b..0000000000 --- a/doc/py_tutorials/py_setup/py_table_of_contents_setup/py_table_of_contents_setup.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. _PY_Table-Of-Content-Setup: - -Introduction to OpenCV ------------------------------------------------------------ - -* :ref:`Intro` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |Intro_1| Getting Started with OpenCV-Python - - =========== ====================================================== - - .. |Intro_1| image:: images/opencv_logo.jpg - :height: 90pt - :width: 90pt - - - -* :ref:`Install-OpenCV-Python-in-Windows` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |Install_1| Set Up OpenCV-Python in Windows - - =========== ====================================================== - - .. |Install_1| image:: images/windows_logo.jpg - :height: 90pt - :width: 90pt - -* :ref:`Install-OpenCV-Python-in-Fedora` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |Install_2| Set Up OpenCV-Python in Fedora - - =========== ====================================================== - - .. |Install_2| image:: images/fedora_logo.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_intro/py_intro - ../py_setup_in_windows/py_setup_in_windows - ../py_setup_in_fedora/py_setup_in_fedora diff --git a/doc/py_tutorials/py_tutorials.rst b/doc/py_tutorials/py_tutorials.rst deleted file mode 100644 index 7e4ec86f7f..0000000000 --- a/doc/py_tutorials/py_tutorials.rst +++ /dev/null @@ -1,195 +0,0 @@ -####################### -OpenCV-Python Tutorials -####################### - -* :ref:`PY_Table-Of-Content-Setup` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Introduct| Learn how to setup OpenCV-Python on your computer! - - =========== ======================================================= - - .. |Introduct| image:: images/intro.png - :height: 80pt - :width: 80pt - :alt: Introduction Icon - -* :ref:`PY_Table-Of-Content-Gui` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Gui| Here you will learn how to display and save images and videos, control mouse events and create trackbar. - =========== ======================================================= - - .. |Gui| image:: images/gui.jpg - :height: 80pt - :width: 80pt - :alt: gui Icon - -* :ref:`PY_Table-Of-Content-Core` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Core| In this section you will learn basic operations on image like pixel editing, geometric transformations, code optimization, some mathematical tools etc. - - =========== ======================================================= - - .. |Core| image:: images/core.jpg - :height: 80pt - :width: 80pt - :alt: core Icon - - -* :ref:`PY_Table-Of-Content-ImgProc` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |ImgProc| In this section you will learn different image processing functions inside OpenCV. - - =========== ======================================================= - - .. |ImgProc| image:: images/imgproc.jpg - :height: 80pt - :width: 80pt - :alt: imgproc Icon - -* :ref:`PY_Table-Of-Content-Feature2D` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Feature2D| In this section you will learn about feature detectors and descriptors - - =========== ======================================================= - - .. |Feature2D| image:: images/featureicon.jpg - :height: 80pt - :width: 80pt - :alt: imgproc Icon - - -* :ref:`PY_Table-Of-Content-Video` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Video| In this section you will learn different techniques to work with videos like object tracking etc. - - =========== ======================================================= - - .. |Video| image:: images/videoicon.jpg - :height: 80pt - :width: 80pt - :alt: imgproc Icon - - -* :ref:`PY_Table-Of-Content-Calib` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Calib| In this section we will learn about camera calibration, stereo imaging etc. - - =========== ======================================================= - - .. |Calib| image:: images/calib3d_icon.jpg - :height: 80pt - :width: 80pt - :alt: Calib Icon - - - -* :ref:`PY_Table-Of-Content-ML` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |ML| In this section you will learn different image processing functions inside OpenCV. - - =========== ======================================================= - - .. |ML| image:: images/MachineLearnings.jpg - :height: 80pt - :width: 80pt - :alt: ML Icon - - -* :ref:`PY_Table-Of-Content-Photo` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Photo| In this section you will learn different computational photography techniques like image denoising etc. - - =========== ======================================================= - - .. |Photo| image:: images/photoicon.jpg - :height: 80pt - :width: 80pt - :alt: ML Icon - - -* :ref:`PY_Table-Of-Content-Objdetection` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Objde| In this section you will object detection techniques like face detection etc. - - =========== ======================================================= - - .. |Objde| image:: images/obj_icon.jpg - :height: 80pt - :width: 80pt - :alt: OD Icon - - -* :ref:`PY_Table-Of-Content-Bindings` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ===================================================================== - |PyBin| In this section, we will see how OpenCV-Python bindings are generated - - =========== ===================================================================== - - .. |PyBin| image:: images/obj_icon.jpg - :height: 80pt - :width: 80pt - :alt: OD Icon - -.. raw:: latex - - \pagebreak - -.. toctree:: - :maxdepth: 2 - :hidden: - - py_setup/py_table_of_contents_setup/py_table_of_contents_setup - py_gui/py_table_of_contents_gui/py_table_of_contents_gui - py_core/py_table_of_contents_core/py_table_of_contents_core - py_imgproc/py_table_of_contents_imgproc/py_table_of_contents_imgproc - py_feature2d/py_table_of_contents_feature2d/py_table_of_contents_feature2d - py_video/py_table_of_contents_video/py_table_of_contents_video - py_calib3d/py_table_of_contents_calib3d/py_table_of_contents_calib3d - py_ml/py_table_of_contents_ml/py_table_of_contents_ml - py_photo/py_table_of_contents_photo/py_table_of_contents_photo - py_objdetect/py_table_of_contents_objdetect/py_table_of_contents_objdetect - py_bindings/py_table_of_contents_bindings/py_table_of_contents_bindings diff --git a/doc/py_tutorials/py_video/py_table_of_contents_video/images/background.jpg b/doc/py_tutorials/py_video/images/background.jpg similarity index 100% rename from doc/py_tutorials/py_video/py_table_of_contents_video/images/background.jpg rename to doc/py_tutorials/py_video/images/background.jpg diff --git a/doc/py_tutorials/py_video/py_table_of_contents_video/images/camshift.jpg b/doc/py_tutorials/py_video/images/camshift.jpg similarity index 100% rename from doc/py_tutorials/py_video/py_table_of_contents_video/images/camshift.jpg rename to doc/py_tutorials/py_video/images/camshift.jpg diff --git a/doc/py_tutorials/py_video/py_table_of_contents_video/images/lucas.jpg b/doc/py_tutorials/py_video/images/lucas.jpg similarity index 100% rename from doc/py_tutorials/py_video/py_table_of_contents_video/images/lucas.jpg rename to doc/py_tutorials/py_video/images/lucas.jpg diff --git a/doc/py_tutorials/py_video/py_table_of_contents_video/images/opticalflow.jpeg b/doc/py_tutorials/py_video/images/opticalflow.jpeg similarity index 100% rename from doc/py_tutorials/py_video/py_table_of_contents_video/images/opticalflow.jpeg rename to doc/py_tutorials/py_video/images/opticalflow.jpeg diff --git a/doc/py_tutorials/py_video/py_bg_subtraction/py_bg_subtraction.rst b/doc/py_tutorials/py_video/py_bg_subtraction/py_bg_subtraction.rst deleted file mode 100644 index 54bac5bcab..0000000000 --- a/doc/py_tutorials/py_video/py_bg_subtraction/py_bg_subtraction.rst +++ /dev/null @@ -1,162 +0,0 @@ -.. _py_background_subtraction: - - -Background Subtraction -**************************** - -Goal -======= - -In this chapter, - - * We will familiarize with the background subtraction methods available in OpenCV. - -Basics -============= - -Background subtraction is a major preprocessing steps in many vision based applications. For example, consider the cases like visitor counter where a static camera takes the number of visitors entering or leaving the room, or a traffic camera extracting information about the vehicles etc. In all these cases, first you need to extract the person or vehicles alone. Technically, you need to extract the moving foreground from static background. - -If you have an image of background alone, like image of the room without visitors, image of the road without vehicles etc, it is an easy job. Just subtract the new image from the background. You get the foreground objects alone. But in most of the cases, you may not have such an image, so we need to extract the background from whatever images we have. It become more complicated when there is shadow of the vehicles. Since shadow is also moving, simple subtraction will mark that also as foreground. It complicates things. - -Several algorithms were introduced for this purpose. OpenCV has implemented three such algorithms which is very easy to use. We will see them one-by-one. - - -BackgroundSubtractorMOG ------------------------------------ - -It is a Gaussian Mixture-based Background/Foreground Segmentation Algorithm. It was introduced in the paper "An improved adaptive background mixture model for real-time tracking with shadow detection" by P. KadewTraKuPong and R. Bowden in 2001. It uses a method to model each background pixel by a mixture of K Gaussian distributions (K = 3 to 5). The weights of the mixture represent the time proportions that those colours stay in the scene. The probable background colours are the ones which stay longer and more static. - -While coding, we need to create a background object using the function, **cv2.createBackgroundSubtractorMOG()**. It has some optional parameters like length of history, number of gaussian mixtures, threshold etc. It is all set to some default values. Then inside the video loop, use ``backgroundsubtractor.apply()`` method to get the foreground mask. - -See a simple example below: -:: - - import numpy as np - import cv2 - - cap = cv2.VideoCapture('vtest.avi') - - fgbg = cv2.createBackgroundSubtractorMOG() - - while(1): - ret, frame = cap.read() - - fgmask = fgbg.apply(frame) - - cv2.imshow('frame',fgmask) - k = cv2.waitKey(30) & 0xff - if k == 27: - break - - cap.release() - cv2.destroyAllWindows() - - -( All the results are shown at the end for comparison). - - -BackgroundSubtractorMOG2 ------------------------------------- - -It is also a Gaussian Mixture-based Background/Foreground Segmentation Algorithm. It is based on two papers by Z.Zivkovic, "Improved adaptive Gausian mixture model for background subtraction" in 2004 and "Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction" in 2006. One important feature of this algorithm is that it selects the appropriate number of gaussian distribution for each pixel. (Remember, in last case, we took a K gaussian distributions throughout the algorithm). It provides better adaptibility to varying scenes due illumination changes etc. - -As in previous case, we have to create a background subtractor object. Here, you have an option of selecting whether shadow to be detected or not. If ``detectShadows = True`` (which is so by default), it detects and marks shadows, but decreases the speed. Shadows will be marked in gray color. -:: - - import numpy as np - import cv2 - - cap = cv2.VideoCapture('vtest.avi') - - fgbg = cv2.createBackgroundSubtractorMOG2() - - while(1): - ret, frame = cap.read() - - fgmask = fgbg.apply(frame) - - cv2.imshow('frame',fgmask) - k = cv2.waitKey(30) & 0xff - if k == 27: - break - - cap.release() - cv2.destroyAllWindows() - -(Results given at the end) - - -BackgroundSubtractorGMG ------------------------------------ - -This algorithm combines statistical background image estimation and per-pixel Bayesian segmentation. It was introduced by Andrew B. Godbehere, Akihiro Matsukawa, Ken Goldberg in their paper "Visual Tracking of Human Visitors under Variable-Lighting Conditions for a Responsive Audio Art Installation" in 2012. As per the paper, the system ran a successful interactive audio art installation called “Are We There Yet?†from March 31 - July 31 2011 at the Contemporary Jewish Museum in San Francisco, California. - -It uses first few (120 by default) frames for background modelling. It employs probabilistic foreground segmentation algorithm that identifies possible foreground objects using Bayesian inference. The estimates are adaptive; newer observations are more heavily weighted than old observations to accommodate variable illumination. Several morphological filtering operations like closing and opening are done to remove unwanted noise. You will get a black window during first few frames. - -It would be better to apply morphological opening to the result to remove the noises. -:: - - import numpy as np - import cv2 - - cap = cv2.VideoCapture('vtest.avi') - - kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3)) - fgbg = cv2.createBackgroundSubtractorGMG() - - while(1): - ret, frame = cap.read() - - fgmask = fgbg.apply(frame) - fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel) - - cv2.imshow('frame',fgmask) - k = cv2.waitKey(30) & 0xff - if k == 27: - break - - cap.release() - cv2.destroyAllWindows() - - -Results -=========== - - -**Original Frame** - -Below image shows the 200th frame of a video - - .. image:: images/resframe.jpg - :alt: Original frame - :align: center - -**Result of BackgroundSubtractorMOG** - - .. image:: images/resmog.jpg - :alt: Result of BackgroundSubtractorMOG - :align: center - -**Result of BackgroundSubtractorMOG2** - -Gray color region shows shadow region. - - .. image:: images/resmog2.jpg - :alt: Result of BackgroundSubtractorMOG2 - :align: center - -**Result of BackgroundSubtractorGMG** - -Noise is removed with morphological opening. - - .. image:: images/resgmg.jpg - :alt: Result of BackgroundSubtractorGMG - :align: center - - -Additional Resources -============================= - - -Exercises -================= diff --git a/doc/py_tutorials/py_video/py_lucas_kanade/py_lucas_kanade.rst b/doc/py_tutorials/py_video/py_lucas_kanade/py_lucas_kanade.rst deleted file mode 100644 index cb889a7055..0000000000 --- a/doc/py_tutorials/py_video/py_lucas_kanade/py_lucas_kanade.rst +++ /dev/null @@ -1,212 +0,0 @@ -.. _Lucas_Kanade: - - -Optical Flow -********************************************* - -Goal -======= - -In this chapter, - * We will understand the concepts of optical flow and its estimation using Lucas-Kanade method. - * We will use functions like **cv2.calcOpticalFlowPyrLK()** to track feature points in a video. - - -Optical Flow -================ - -Optical flow is the pattern of apparent motion of image objects between two consecutive frames caused by the movemement of object or camera. It is 2D vector field where each vector is a displacement vector showing the movement of points from first frame to second. Consider the image below (Image Courtesy: `Wikipedia article on Optical Flow `_). - - - .. image:: images/optical_flow_basic1.jpg - :alt: Optical Flow - :align: center - -It shows a ball moving in 5 consecutive frames. The arrow shows its displacement vector. Optical flow has many applications in areas like : - - * Structure from Motion - * Video Compression - * Video Stabilization ... - -Optical flow works on several assumptions: - -1. The pixel intensities of an object do not change between consecutive frames. -2. Neighbouring pixels have similar motion. - -Consider a pixel :math:`I(x,y,t)` in first frame (Check a new dimension, time, is added here. Earlier we were working with images only, so no need of time). It moves by distance :math:`(dx,dy)` in next frame taken after :math:`dt` time. So since those pixels are the same and intensity does not change, we can say, - -.. math:: - - I(x,y,t) = I(x+dx, y+dy, t+dt) - -Then take taylor series approximation of right-hand side, remove common terms and divide by :math:`dt` to get the following equation: - -.. math:: - - f_x u + f_y v + f_t = 0 \; - -where: - -.. math:: - - f_x = \frac{\partial f}{\partial x} \; ; \; f_y = \frac{\partial f}{\partial x} - - u = \frac{dx}{dt} \; ; \; v = \frac{dy}{dt} - - -Above equation is called Optical Flow equation. In it, we can find :math:`f_x` and :math:`f_y`, they are image gradients. Similarly :math:`f_t` is the gradient along time. But :math:`(u,v)` is unknown. We cannot solve this one equation with two unknown variables. So several methods are provided to solve this problem and one of them is Lucas-Kanade. - -Lucas-Kanade method -------------------------- - -We have seen an assumption before, that all the neighbouring pixels will have similar motion. Lucas-Kanade method takes a 3x3 patch around the point. So all the 9 points have the same motion. We can find :math:`(f_x, f_y, f_t)` for these 9 points. So now our problem becomes solving 9 equations with two unknown variables which is over-determined. A better solution is obtained with least square fit method. Below is the final solution which is two equation-two unknown problem and solve to get the solution. - -.. math:: - - \begin{bmatrix} u \\ v \end{bmatrix} = - \begin{bmatrix} - \sum_{i}{f_{x_i}}^2 & \sum_{i}{f_{x_i} f_{y_i} } \\ - \sum_{i}{f_{x_i} f_{y_i}} & \sum_{i}{f_{y_i}}^2 - \end{bmatrix}^{-1} - \begin{bmatrix} - - \sum_{i}{f_{x_i} f_{t_i}} \\ - - \sum_{i}{f_{y_i} f_{t_i}} - \end{bmatrix} - - -( Check similarity of inverse matrix with Harris corner detector. It denotes that corners are better points to be tracked.) - -So from user point of view, idea is simple, we give some points to track, we receive the optical flow vectors of those points. But again there are some problems. Until now, we were dealing with small motions. So it fails when there is large motion. So again we go for pyramids. When we go up in the pyramid, small motions are removed and large motions becomes small motions. So applying Lucas-Kanade there, we get optical flow along with the scale. - - -Lucas-Kanade Optical Flow in OpenCV -======================================= - -OpenCV provides all these in a single function, **cv2.calcOpticalFlowPyrLK()**. Here, we create a simple application which tracks some points in a video. To decide the points, we use **cv2.goodFeaturesToTrack()**. We take the first frame, detect some Shi-Tomasi corner points in it, then we iteratively track those points using Lucas-Kanade optical flow. For the function **cv2.calcOpticalFlowPyrLK()** we pass the previous frame, previous points and next frame. It returns next points along with some status numbers which has a value of 1 if next point is found, else zero. We iteratively pass these next points as previous points in next step. See the code below: -:: - - import numpy as np - import cv2 - - cap = cv2.VideoCapture('slow.flv') - - # params for ShiTomasi corner detection - feature_params = dict( maxCorners = 100, - qualityLevel = 0.3, - minDistance = 7, - blockSize = 7 ) - - # Parameters for lucas kanade optical flow - lk_params = dict( winSize = (15,15), - maxLevel = 2, - criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)) - - # Create some random colors - color = np.random.randint(0,255,(100,3)) - - # Take first frame and find corners in it - ret, old_frame = cap.read() - old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY) - p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params) - - # Create a mask image for drawing purposes - mask = np.zeros_like(old_frame) - - while(1): - ret,frame = cap.read() - frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) - - # calculate optical flow - p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params) - - # Select good points - good_new = p1[st==1] - good_old = p0[st==1] - - # draw the tracks - for i,(new,old) in enumerate(zip(good_new,good_old)): - a,b = new.ravel() - c,d = old.ravel() - mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2) - frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1) - img = cv2.add(frame,mask) - - cv2.imshow('frame',img) - k = cv2.waitKey(30) & 0xff - if k == 27: - break - - # Now update the previous frame and previous points - old_gray = frame_gray.copy() - p0 = good_new.reshape(-1,1,2) - - cv2.destroyAllWindows() - cap.release() - - -(This code doesn't check how correct are the next keypoints. So even if any feature point disappears in image, there is a chance that optical flow finds the next point which may look close to it. So actually for a robust tracking, corner points should be detected in particular intervals. OpenCV samples comes up with such a sample which finds the feature points at every 5 frames. It also run a backward-check of the optical flow points got to select only good ones. Check ``samples/python2/lk_track.py``). - -See the results we got: - - .. image:: images/opticalflow_lk.jpg - :alt: Lucas-Kanade method for optical flow - :align: center - - -Dense Optical Flow in OpenCV -============================== - -Lucas-Kanade method computes optical flow for a sparse feature set (in our example, corners detected using Shi-Tomasi algorithm). OpenCV provides another algorithm to find the dense optical flow. It computes the optical flow for all the points in the frame. It is based on Gunner Farneback's algorithm which is explained in "Two-Frame Motion Estimation Based on Polynomial Expansion" by Gunner Farneback in 2003. - -Below sample shows how to find the dense optical flow using above algorithm. We get a 2-channel array with optical flow vectors, :math:`(u,v)`. We find their magnitude and direction. We color code the result for better visualization. Direction corresponds to Hue value of the image. Magnitude corresponds to Value plane. See the code below: -:: - - import cv2 - import numpy as np - cap = cv2.VideoCapture("vtest.avi") - - ret, frame1 = cap.read() - prvs = cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY) - hsv = np.zeros_like(frame1) - hsv[...,1] = 255 - - while(1): - ret, frame2 = cap.read() - next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY) - - flow = cv2.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0) - - mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1]) - hsv[...,0] = ang*180/np.pi/2 - hsv[...,2] = cv2.normalize(mag,None,0,255,cv2.NORM_MINMAX) - rgb = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR) - - cv2.imshow('frame2',rgb) - k = cv2.waitKey(30) & 0xff - if k == 27: - break - elif k == ord('s'): - cv2.imwrite('opticalfb.png',frame2) - cv2.imwrite('opticalhsv.png',rgb) - prvs = next - - cap.release() - cv2.destroyAllWindows() - -See the result below: - - .. image:: images/opticalfb.jpg - :alt: Dense Optical Flow - :align: center - -OpenCV comes with a more advanced sample on dense optical flow, please see ``samples/python2/opt_flow.py``. - -Additional Resources -======================== - - -Exercises -=========== - -#. Check the code in ``samples/python2/lk_track.py``. Try to understand the code. -#. Check the code in ``samples/python2/opt_flow.py``. Try to understand the code. diff --git a/doc/py_tutorials/py_video/py_meanshift/py_meanshift.rst b/doc/py_tutorials/py_video/py_meanshift/py_meanshift.rst deleted file mode 100644 index 5039e272b6..0000000000 --- a/doc/py_tutorials/py_video/py_meanshift/py_meanshift.rst +++ /dev/null @@ -1,184 +0,0 @@ -.. _meanshift: - - -Meanshift and Camshift -**************************** - - -Goal -======== - -In this chapter, - - * We will learn about Meanshift and Camshift algorithms to find and track objects in videos. - - -Meanshift -============ - -The intuition behind the meanshift is simple. Consider you have a set of points. (It can be a pixel distribution like histogram backprojection). You are given a small window (maybe a circle) and you have to move that window to the area of maximum pixel density (or maximum number of points). It is illustrated in the simple image given below: - - .. image:: images/meanshift_basics.jpg - :alt: Intuition behind meanshift - :align: center - - -The initial window is shown in blue circle with the name "C1". Its original center is marked in blue rectangle, named "C1_o". But if you find the centroid of the points inside that window, you will get the point "C1_r" (marked in small blue circle) which is the real centroid of window. Surely they don't match. So move your window such that circle of the new window matches with previous centroid. Again find the new centroid. Most probably, it won't match. So move it again, and continue the iterations such that center of window and its centroid falls on the same location (or with a small desired error). So finally what you obtain is a window with maximum pixel distribution. It is marked with green circle, named "C2". As you can see in image, it has maximum number of points. The whole process is demonstrated on a static image below: - - .. image:: images/meanshift_face.gif - :alt: Meanshift on static image - :align: center - -So we normally pass the histogram backprojected image and initial target location. When the object moves, obviously the movement is reflected in histogram backprojected image. As a result, meanshift algorithm moves our window to the new location with maximum density. - - -Meanshift in OpenCV ---------------------- - -To use meanshift in OpenCV, first we need to setup the target, find its histogram so that we can backproject the target on each frame for calculation of meanshift. We also need to provide initial location of window. For histogram, only Hue is considered here. Also, to avoid false values due to low light, low light values are discarded using **cv2.inRange()** function. -:: - - import numpy as np - import cv2 - - cap = cv2.VideoCapture('slow.flv') - - # take first frame of the video - ret,frame = cap.read() - - # setup initial location of window - r,h,c,w = 250,90,400,125 # simply hardcoded the values - track_window = (c,r,w,h) - - # set up the ROI for tracking - roi = frame[r:r+h, c:c+w] - hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) - mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.))) - roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180]) - cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX) - - # Setup the termination criteria, either 10 iteration or move by atleast 1 pt - term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 ) - - while(1): - ret ,frame = cap.read() - - if ret == True: - hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) - dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1) - - # apply meanshift to get the new location - ret, track_window = cv2.meanShift(dst, track_window, term_crit) - - # Draw it on image - x,y,w,h = track_window - img2 = cv2.rectangle(frame, (x,y), (x+w,y+h), 255,2) - cv2.imshow('img2',img2) - - k = cv2.waitKey(60) & 0xff - if k == 27: - break - else: - cv2.imwrite(chr(k)+".jpg",img2) - - else: - break - - cv2.destroyAllWindows() - cap.release() - - -Three frames in a video I used is given below: - - .. image:: images/meanshift_result.jpg - :alt: Meanshift result - :align: center - - -Camshift -============ - -Did you closely watch the last result? There is a problem. Our window always has the same size when car is farther away and it is very close to camera. That is not good. We need to adapt the window size with size and rotation of the target. Once again, the solution came from "OpenCV Labs" and it is called CAMshift (Continuously Adaptive Meanshift) published by Gary Bradsky in his paper "Computer Vision Face Tracking for Use in a Perceptual User Interface" in 1988. - -It applies meanshift first. Once meanshift converges, it updates the size of the window as, :math:`s = 2 \times \sqrt{\frac{M_{00}}{256}}`. It also calculates the orientation of best fitting ellipse to it. Again it applies the meanshift with new scaled search window and previous window location. The process is continued until required accuracy is met. - - .. image:: images/camshift_face.gif - :alt: Meanshift on static image - :align: center - - -Camshift in OpenCV ---------------------- - -It is almost same as meanshift, but it returns a rotated rectangle (that is our result) and box parameters (used to be passed as search window in next iteration). See the code below: -:: - - import numpy as np - import cv2 - - cap = cv2.VideoCapture('slow.flv') - - # take first frame of the video - ret,frame = cap.read() - - # setup initial location of window - r,h,c,w = 250,90,400,125 # simply hardcoded the values - track_window = (c,r,w,h) - - # set up the ROI for tracking - roi = frame[r:r+h, c:c+w] - hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) - mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.))) - roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180]) - cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX) - - # Setup the termination criteria, either 10 iteration or move by atleast 1 pt - term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 ) - - while(1): - ret ,frame = cap.read() - - if ret == True: - hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) - dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1) - - # apply meanshift to get the new location - ret, track_window = cv2.CamShift(dst, track_window, term_crit) - - # Draw it on image - pts = cv2.boxPoints(ret) - pts = np.int0(pts) - img2 = cv2.polylines(frame,[pts],True, 255,2) - cv2.imshow('img2',img2) - - k = cv2.waitKey(60) & 0xff - if k == 27: - break - else: - cv2.imwrite(chr(k)+".jpg",img2) - - else: - break - - cv2.destroyAllWindows() - cap.release() - -Three frames of the result is shown below: - - .. image:: images/camshift_result.jpg - :alt: Camshift result - :align: center - - -Additional Resources -============================= - -#. French Wikipedia page on `Camshift `_. (The two animations are taken from here) - -#. Bradski, G.R., "Real time face and object tracking as a component of a perceptual user interface," Applications of Computer Vision, 1998. WACV '98. Proceedings., Fourth IEEE Workshop on , vol., no., pp.214,219, 19-21 Oct 1998 - - -Exercises -=============== - -#. OpenCV comes with a Python sample on interactive demo of camshift. Use it, hack it, understand it. diff --git a/doc/py_tutorials/py_video/py_table_of_contents_video/py_table_of_contents_video.markdown b/doc/py_tutorials/py_video/py_table_of_contents_video.markdown similarity index 100% rename from doc/py_tutorials/py_video/py_table_of_contents_video/py_table_of_contents_video.markdown rename to doc/py_tutorials/py_video/py_table_of_contents_video.markdown diff --git a/doc/py_tutorials/py_video/py_table_of_contents_video/py_table_of_contents_video.rst b/doc/py_tutorials/py_video/py_table_of_contents_video/py_table_of_contents_video.rst deleted file mode 100644 index f076cbd705..0000000000 --- a/doc/py_tutorials/py_video/py_table_of_contents_video/py_table_of_contents_video.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. _PY_Table-Of-Content-Video: - -Video Analysis ------------------------------------------- - -* :ref:`meanshift` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |vdo_1| We have already seen an example of color-based tracking. It is simpler. This time, we see significantly better algorithms like "Meanshift", and its upgraded version, "Camshift" to find and track them. - - =========== ====================================================== - - .. |vdo_1| image:: images/camshift.jpg - :height: 90pt - :width: 90pt - - -* :ref:`Lucas_Kanade` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |vdo_2| Now let's discuss an important concept, "Optical Flow", which is related to videos and has many applications. - =========== ====================================================== - - .. |vdo_2| image:: images/opticalflow.jpeg - :height: 90pt - :width: 90pt - - -* :ref:`py_background_subtraction` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |vdo_b| In several applications, we need to extract foreground for further operations like object tracking. Background Subtraction is a well-known method in those cases. - =========== ====================================================== - - .. |vdo_b| image:: images/background.jpg - :height: 90pt - :width: 90pt - - - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../py_meanshift/py_meanshift - ../py_lucas_kanade/py_lucas_kanade - ../py_bg_subtraction/py_bg_subtraction diff --git a/doc/reformat.py b/doc/reformat.py deleted file mode 100755 index 017efebb38..0000000000 --- a/doc/reformat.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python - -import os, sys, re - -finput=open(sys.argv[1], "rt") - -# read the whole file content to s -s = "".join(finput.readlines()) -finput.close() - -# normalize line endings -s = re.sub(r"\r\n", "\n", s) - -# remove trailing whitespaces -s = re.sub(r"[ \t]+\n", "\n", s) - -# compress multiple empty lines -for i in range(5): - s = re.sub(r"\n\n\n", "\n\n", s) - -# remove empty line before ".." that terminates a code block -s = re.sub(r"\n\n\.\.\n", "\n..\n", s) - -# move :: starting a code block to the end of previous line -s = re.sub(r"\n\n::\n", " ::\n", s) - -# remove extra line breaks before/after _ or , -s = re.sub(r"\n[ \t]*([_,])\n", r"\1", s) - -# remove extra line breaks after ` -s = re.sub(r"`\n", "` ", s) - -# remove extra line breaks before ` -s = re.sub(r"\n[ \t]*`", " `", s) - -# remove links to wiki -s = re.sub(r"\n[ \t]*`id=\d[^`]+`__\n", "", s) - -# remove trailing whitespaces one more time -s = re.sub(r"[ \t]+\n", "\n", s) - -foutput=open(sys.argv[2], "wt") -foutput.write(s) -foutput.close() diff --git a/doc/stylesheet.css b/doc/stylesheet.css new file mode 100644 index 0000000000..20b8bc329d --- /dev/null +++ b/doc/stylesheet.css @@ -0,0 +1,33 @@ +/* The standard CSS for doxygen 1.8.6 */ + +body, table, div, p, dl { + font: 400 14px/22px Helvetica, 'Segoe UI', Arial, freesans, sans-serif; + word-wrap: break-word; +} + +code { + font: 12px Consolas, "Liberation Mono", Courier, monospace; + font-size: 85%; + white-space: pre-wrap; + padding: 1px 5px; + padding: 0; + background-color: #ddd; + vertical-align: baseline; +} + +body { + background-image: url(bodybg.png); + margin: 0 auto; +} + +div.contents { + width: 980px; + margin: 0 auto; + padding: 15px 15px; + border: 1px solid rgb(10, 80, 122); + background-color: #fff; +} + +span.arrow { + height: 13px; +} diff --git a/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown b/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown index 0f1eaf90c6..0b23643964 100644 --- a/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown +++ b/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown @@ -77,13 +77,13 @@ Source code You may also find the source code in the `samples/cpp/tutorial_code/calib3d/camera_calibration/` folder of the OpenCV source library or [download it from here -](samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp). The program has a +](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp). The program has a single argument: the name of its configuration file. If none is given then it will try to open the one named "default.xml". [Here's a sample configuration file -](samples/cpp/tutorial_code/calib3d/camera_calibration/in_VID5.xml) in XML format. In the +](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/calib3d/camera_calibration/in_VID5.xml) in XML format. In the configuration file you may choose to use camera as an input, a video file or an image list. If you opt for the last one, you will need to create a configuration file where you enumerate the images to -use. Here's [an example of this ](samples/cpp/tutorial_code/calib3d/camera_calibration/VID5.xml). +use. Here's [an example of this ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/calib3d/camera_calibration/VID5.xml). The important part to remember is that the images need to be specified using the absolute path or the relative one from your application's working directory. You may find all this in the samples directory mentioned above. diff --git a/doc/tutorials/calib3d/camera_calibration/camera_calibration.rst b/doc/tutorials/calib3d/camera_calibration/camera_calibration.rst deleted file mode 100644 index ff9417ed15..0000000000 --- a/doc/tutorials/calib3d/camera_calibration/camera_calibration.rst +++ /dev/null @@ -1,444 +0,0 @@ -.. _cameraCalibrationOpenCV: - -Camera calibration With OpenCV -****************************** - -Cameras have been around for a long-long time. However, with the introduction of the cheap *pinhole* cameras in the late 20th century, they became a common occurrence in our everyday life. Unfortunately, this cheapness comes with its price: significant distortion. Luckily, these are constants and with a calibration and some remapping we can correct this. Furthermore, with calibration you may also determine the relation between the camera's natural units (pixels) and the real world units (for example millimeters). - -Theory -====== - -For the distortion OpenCV takes into account the radial and tangential factors. For the radial factor one uses the following formula: - -.. math:: - - x_{corrected} = x( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6) \\ - y_{corrected} = y( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6) - -So for an old pixel point at :math:`(x,y)` coordinates in the input image, its position on the corrected output image will be :math:`(x_{corrected} y_{corrected})`. The presence of the radial distortion manifests in form of the "barrel" or "fish-eye" effect. - -Tangential distortion occurs because the image taking lenses are not perfectly parallel to the imaging plane. It can be corrected via the formulas: - -.. math:: - - x_{corrected} = x + [ 2p_1xy + p_2(r^2+2x^2)] \\ - y_{corrected} = y + [ p_1(r^2+ 2y^2)+ 2p_2xy] - -So we have five distortion parameters which in OpenCV are presented as one row matrix with 5 columns: - -.. math:: - - Distortion_{coefficients}=(k_1 \hspace{10pt} k_2 \hspace{10pt} p_1 \hspace{10pt} p_2 \hspace{10pt} k_3) - -Now for the unit conversion we use the following formula: - -.. math:: - - \left [ \begin{matrix} x \\ y \\ w \end{matrix} \right ] = \left [ \begin{matrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix} \right ] \left [ \begin{matrix} X \\ Y \\ Z \end{matrix} \right ] - -Here the presence of :math:`w` is explained by the use of homography coordinate system (and :math:`w=Z`). The unknown parameters are :math:`f_x` and :math:`f_y` (camera focal lengths) and :math:`(c_x, c_y)` which are the optical centers expressed in pixels coordinates. If for both axes a common focal length is used with a given :math:`a` aspect ratio (usually 1), then :math:`f_y=f_x*a` and in the upper formula we will have a single focal length :math:`f`. The matrix containing these four parameters is referred to as the *camera matrix*. While the distortion coefficients are the same regardless of the camera resolutions used, these should be scaled along with the current resolution from the calibrated resolution. - -The process of determining these two matrices is the calibration. Calculation of these parameters is done through basic geometrical equations. The equations used depend on the chosen calibrating objects. Currently OpenCV supports three types of objects for calibration: - -.. container:: enumeratevisibleitemswithsquare - - + Classical black-white chessboard - + Symmetrical circle pattern - + Asymmetrical circle pattern - -Basically, you need to take snapshots of these patterns with your camera and let OpenCV find them. Each found pattern results in a new equation. To solve the equation you need at least a predetermined number of pattern snapshots to form a well-posed equation system. This number is higher for the chessboard pattern and less for the circle ones. For example, in theory the chessboard pattern requires at least two snapshots. However, in practice we have a good amount of noise present in our input images, so for good results you will probably need at least 10 good snapshots of the input pattern in different positions. - -Goal -==== - -The sample application will: - -.. container:: enumeratevisibleitemswithsquare - - + Determine the distortion matrix - + Determine the camera matrix - + Take input from Camera, Video and Image file list - + Read configuration from XML/YAML file - + Save the results into XML/YAML file - + Calculate re-projection error - -Source code -=========== - -You may also find the source code in the :file:`samples/cpp/tutorial_code/calib3d/camera_calibration/` folder of the OpenCV source library or :download:`download it from here <../../../../samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp>`. The program has a single argument: the name of its configuration file. If none is given then it will try to open the one named "default.xml". :download:`Here's a sample configuration file <../../../../samples/cpp/tutorial_code/calib3d/camera_calibration/in_VID5.xml>` in XML format. In the configuration file you may choose to use camera as an input, a video file or an image list. If you opt for the last one, you will need to create a configuration file where you enumerate the images to use. Here's :download:`an example of this <../../../../samples/cpp/tutorial_code/calib3d/camera_calibration/VID5.xml>`. The important part to remember is that the images need to be specified using the absolute path or the relative one from your application's working directory. You may find all this in the samples directory mentioned above. - -The application starts up with reading the settings from the configuration file. Although, this is an important part of it, it has nothing to do with the subject of this tutorial: *camera calibration*. Therefore, I've chosen not to post the code for that part here. Technical background on how to do this you can find in the :ref:`fileInputOutputXMLYAML` tutorial. - -Explanation -=========== - -1. **Read the settings.** - - .. code-block:: cpp - - Settings s; - const string inputSettingsFile = argc > 1 ? argv[1] : "default.xml"; - FileStorage fs(inputSettingsFile, FileStorage::READ); // Read the settings - if (!fs.isOpened()) - { - cout << "Could not open the configuration file: \"" << inputSettingsFile << "\"" << endl; - return -1; - } - fs["Settings"] >> s; - fs.release(); // close Settings file - - if (!s.goodInput) - { - cout << "Invalid input detected. Application stopping. " << endl; - return -1; - } - - For this I've used simple OpenCV class input operation. After reading the file I've an additional post-processing function that checks validity of the input. Only if all inputs are good then *goodInput* variable will be true. - -#. **Get next input, if it fails or we have enough of them - calibrate**. After this we have a big loop where we do the following operations: get the next image from the image list, camera or video file. If this fails or we have enough images then we run the calibration process. In case of image we step out of the loop and otherwise the remaining frames will be undistorted (if the option is set) via changing from *DETECTION* mode to the *CALIBRATED* one. - - .. code-block:: cpp - - for(int i = 0;;++i) - { - Mat view; - bool blinkOutput = false; - - view = s.nextImage(); - - //----- If no more image, or got enough, then stop calibration and show result ------------- - if( mode == CAPTURING && imagePoints.size() >= (unsigned)s.nrFrames ) - { - if( runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints)) - mode = CALIBRATED; - else - mode = DETECTION; - } - if(view.empty()) // If no more images then run calibration, save and stop loop. - { - if( imagePoints.size() > 0 ) - runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints); - break; - imageSize = view.size(); // Format input image. - if( s.flipVertical ) flip( view, view, 0 ); - } - - For some cameras we may need to flip the input image. Here we do this too. - -#. **Find the pattern in the current input**. The formation of the equations I mentioned above aims to finding major patterns in the input: in case of the chessboard this are corners of the squares and for the circles, well, the circles themselves. The position of these will form the result which will be written into the *pointBuf* vector. - - .. code-block:: cpp - - vector pointBuf; - - bool found; - switch( s.calibrationPattern ) // Find feature points on the input format - { - case Settings::CHESSBOARD: - found = findChessboardCorners( view, s.boardSize, pointBuf, - CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE); - break; - case Settings::CIRCLES_GRID: - found = findCirclesGrid( view, s.boardSize, pointBuf ); - break; - case Settings::ASYMMETRIC_CIRCLES_GRID: - found = findCirclesGrid( view, s.boardSize, pointBuf, CALIB_CB_ASYMMETRIC_GRID ); - break; - } - - Depending on the type of the input pattern you use either the :calib3d:`findChessboardCorners ` or the :calib3d:`findCirclesGrid ` function. For both of them you pass the current image and the size of the board and you'll get the positions of the patterns. Furthermore, they return a boolean variable which states if the pattern was found in the input (we only need to take into account those images where this is true!). - - Then again in case of cameras we only take camera images when an input delay time is passed. This is done in order to allow user moving the chessboard around and getting different images. Similar images result in similar equations, and similar equations at the calibration step will form an ill-posed problem, so the calibration will fail. For square images the positions of the corners are only approximate. We may improve this by calling the :feature2d:`cornerSubPix ` function. It will produce better calibration result. After this we add a valid inputs result to the *imagePoints* vector to collect all of the equations into a single container. Finally, for visualization feedback purposes we will draw the found points on the input image using :calib3d:`findChessboardCorners ` function. - - .. code-block:: cpp - - if ( found) // If done with success, - { - // improve the found corners' coordinate accuracy for chessboard - if( s.calibrationPattern == Settings::CHESSBOARD) - { - Mat viewGray; - cvtColor(view, viewGray, COLOR_BGR2GRAY); - cornerSubPix( viewGray, pointBuf, Size(11,11), - Size(-1,-1), TermCriteria( TermCriteria::EPS+TermCriteria::MAX_ITER, 30, 0.1 )); - } - - if( mode == CAPTURING && // For camera only take new samples after delay time - (!s.inputCapture.isOpened() || clock() - prevTimestamp > s.delay*1e-3*CLOCKS_PER_SEC) ) - { - imagePoints.push_back(pointBuf); - prevTimestamp = clock(); - blinkOutput = s.inputCapture.isOpened(); - } - - // Draw the corners. - drawChessboardCorners( view, s.boardSize, Mat(pointBuf), found ); - } - -#. **Show state and result to the user, plus command line control of the application**. This part shows text output on the image. - - .. code-block:: cpp - - //----------------------------- Output Text ------------------------------------------------ - string msg = (mode == CAPTURING) ? "100/100" : - mode == CALIBRATED ? "Calibrated" : "Press 'g' to start"; - int baseLine = 0; - Size textSize = getTextSize(msg, 1, 1, 1, &baseLine); - Point textOrigin(view.cols - 2*textSize.width - 10, view.rows - 2*baseLine - 10); - - if( mode == CAPTURING ) - { - if(s.showUndistorsed) - msg = format( "%d/%d Undist", (int)imagePoints.size(), s.nrFrames ); - else - msg = format( "%d/%d", (int)imagePoints.size(), s.nrFrames ); - } - - putText( view, msg, textOrigin, 1, 1, mode == CALIBRATED ? GREEN : RED); - - if( blinkOutput ) - bitwise_not(view, view); - - If we ran calibration and got camera's matrix with the distortion coefficients we may want to correct the image using :imgproc_geometric:`undistort ` function: - - .. code-block:: cpp - - //------------------------- Video capture output undistorted ------------------------------ - if( mode == CALIBRATED && s.showUndistorsed ) - { - Mat temp = view.clone(); - undistort(temp, view, cameraMatrix, distCoeffs); - } - //------------------------------ Show image and check for input commands ------------------- - imshow("Image View", view); - - Then we wait for an input key and if this is *u* we toggle the distortion removal, if it is *g* we start again the detection process, and finally for the *ESC* key we quit the application: - - .. code-block:: cpp - - char key = waitKey(s.inputCapture.isOpened() ? 50 : s.delay); - if( key == ESC_KEY ) - break; - - if( key == 'u' && mode == CALIBRATED ) - s.showUndistorsed = !s.showUndistorsed; - - if( s.inputCapture.isOpened() && key == 'g' ) - { - mode = CAPTURING; - imagePoints.clear(); - } - -#. **Show the distortion removal for the images too**. When you work with an image list it is not possible to remove the distortion inside the loop. Therefore, you must do this after the loop. Taking advantage of this now I'll expand the :imgproc_geometric:`undistort ` function, which is in fact first calls :imgproc_geometric:`initUndistortRectifyMap ` to find transformation matrices and then performs transformation using :imgproc_geometric:`remap ` function. Because, after successful calibration map calculation needs to be done only once, by using this expanded form you may speed up your application: - - .. code-block:: cpp - - if( s.inputType == Settings::IMAGE_LIST && s.showUndistorsed ) - { - Mat view, rview, map1, map2; - initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(), - getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0), - imageSize, CV_16SC2, map1, map2); - - for(int i = 0; i < (int)s.imageList.size(); i++ ) - { - view = imread(s.imageList[i], 1); - if(view.empty()) - continue; - remap(view, rview, map1, map2, INTER_LINEAR); - imshow("Image View", rview); - char c = waitKey(); - if( c == ESC_KEY || c == 'q' || c == 'Q' ) - break; - } - } - -The calibration and save -======================== - -Because the calibration needs to be done only once per camera, it makes sense to save it after a successful calibration. This way later on you can just load these values into your program. Due to this we first make the calibration, and if it succeeds we save the result into an OpenCV style XML or YAML file, depending on the extension you give in the configuration file. - -Therefore in the first function we just split up these two processes. Because we want to save many of the calibration variables we'll create these variables here and pass on both of them to the calibration and saving function. Again, I'll not show the saving part as that has little in common with the calibration. Explore the source file in order to find out how and what: - -.. code-block:: cpp - - - bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs,vector > imagePoints ) - { - vector rvecs, tvecs; - vector reprojErrs; - double totalAvgErr = 0; - - bool ok = runCalibration(s,imageSize, cameraMatrix, distCoeffs, imagePoints, rvecs, tvecs, - reprojErrs, totalAvgErr); - cout << (ok ? "Calibration succeeded" : "Calibration failed") - << ". avg re projection error = " << totalAvgErr ; - - if( ok ) // save only if the calibration was done with success - saveCameraParams( s, imageSize, cameraMatrix, distCoeffs, rvecs ,tvecs, reprojErrs, - imagePoints, totalAvgErr); - return ok; - } - -We do the calibration with the help of the :calib3d:`calibrateCamera ` function. It has the following parameters: - -.. container:: enumeratevisibleitemswithsquare - - + The object points. This is a vector of *Point3f* vector that for each input image describes how should the pattern look. If we have a planar pattern (like a chessboard) then we can simply set all Z coordinates to zero. This is a collection of the points where these important points are present. Because, we use a single pattern for all the input images we can calculate this just once and multiply it for all the other input views. We calculate the corner points with the *calcBoardCornerPositions* function as: - - .. code-block:: cpp - - void calcBoardCornerPositions(Size boardSize, float squareSize, vector& corners, - Settings::Pattern patternType /*= Settings::CHESSBOARD*/) - { - corners.clear(); - - switch(patternType) - { - case Settings::CHESSBOARD: - case Settings::CIRCLES_GRID: - for( int i = 0; i < boardSize.height; ++i ) - for( int j = 0; j < boardSize.width; ++j ) - corners.push_back(Point3f(float( j*squareSize ), float( i*squareSize ), 0)); - break; - - case Settings::ASYMMETRIC_CIRCLES_GRID: - for( int i = 0; i < boardSize.height; i++ ) - for( int j = 0; j < boardSize.width; j++ ) - corners.push_back(Point3f(float((2*j + i % 2)*squareSize), float(i*squareSize), 0)); - break; - } - } - - And then multiply it as: - - .. code-block:: cpp - - vector > objectPoints(1); - calcBoardCornerPositions(s.boardSize, s.squareSize, objectPoints[0], s.calibrationPattern); - objectPoints.resize(imagePoints.size(),objectPoints[0]); - - + The image points. This is a vector of *Point2f* vector which for each input image contains coordinates of the important points (corners for chessboard and centers of the circles for the circle pattern). We have already collected this from :calib3d:`findChessboardCorners ` or :calib3d:`findCirclesGrid ` function. We just need to pass it on. - - + The size of the image acquired from the camera, video file or the images. - - + The camera matrix. If we used the fixed aspect ratio option we need to set the :math:`f_x` to zero: - - .. code-block:: cpp - - cameraMatrix = Mat::eye(3, 3, CV_64F); - if( s.flag & CALIB_FIX_ASPECT_RATIO ) - cameraMatrix.at(0,0) = 1.0; - - + The distortion coefficient matrix. Initialize with zero. - - .. code-block:: cpp - - distCoeffs = Mat::zeros(8, 1, CV_64F); - - + For all the views the function will calculate rotation and translation vectors which transform the object points (given in the model coordinate space) to the image points (given in the world coordinate space). The 7-th and 8-th parameters are the output vector of matrices containing in the i-th position the rotation and translation vector for the i-th object point to the i-th image point. - - + The final argument is the flag. You need to specify here options like fix the aspect ratio for the focal length, assume zero tangential distortion or to fix the principal point. - - .. code-block:: cpp - - double rms = calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, - distCoeffs, rvecs, tvecs, s.flag|CV_CALIB_FIX_K4|CV_CALIB_FIX_K5); - - + The function returns the average re-projection error. This number gives a good estimation of precision of the found parameters. This should be as close to zero as possible. Given the intrinsic, distortion, rotation and translation matrices we may calculate the error for one view by using the :calib3d:`projectPoints ` to first transform the object point to image point. Then we calculate the absolute norm between what we got with our transformation and the corner/circle finding algorithm. To find the average error we calculate the arithmetical mean of the errors calculated for all the calibration images. - - .. code-block:: cpp - - double computeReprojectionErrors( const vector >& objectPoints, - const vector >& imagePoints, - const vector& rvecs, const vector& tvecs, - const Mat& cameraMatrix , const Mat& distCoeffs, - vector& perViewErrors) - { - vector imagePoints2; - int i, totalPoints = 0; - double totalErr = 0, err; - perViewErrors.resize(objectPoints.size()); - - for( i = 0; i < (int)objectPoints.size(); ++i ) - { - projectPoints( Mat(objectPoints[i]), rvecs[i], tvecs[i], cameraMatrix, // project - distCoeffs, imagePoints2); - err = norm(Mat(imagePoints[i]), Mat(imagePoints2), NORM_L2); // difference - - int n = (int)objectPoints[i].size(); - perViewErrors[i] = (float) std::sqrt(err*err/n); // save for this view - totalErr += err*err; // sum it up - totalPoints += n; - } - - return std::sqrt(totalErr/totalPoints); // calculate the arithmetical mean - } - -Results -======= - -Let there be :download:`this input chessboard pattern <../../../pattern.png>` which has a size of 9 X 6. I've used an AXIS IP camera to create a couple of snapshots of the board and saved it into VID5 directory. I've put this inside the :file:`images/CameraCalibration` folder of my working directory and created the following :file:`VID5.XML` file that describes which images to use: - -.. code-block:: xml - - - - - images/CameraCalibration/VID5/xx1.jpg - images/CameraCalibration/VID5/xx2.jpg - images/CameraCalibration/VID5/xx3.jpg - images/CameraCalibration/VID5/xx4.jpg - images/CameraCalibration/VID5/xx5.jpg - images/CameraCalibration/VID5/xx6.jpg - images/CameraCalibration/VID5/xx7.jpg - images/CameraCalibration/VID5/xx8.jpg - - - -Then passed :file:`images/CameraCalibration/VID5/VID5.XML` as an input in the configuration file. Here's a chessboard pattern found during the runtime of the application: - -.. image:: images/fileListImage.jpg - :alt: A found chessboard - :align: center - -After applying the distortion removal we get: - -.. image:: images/fileListImageUnDist.jpg - :alt: Distortion removal for File List - :align: center - -The same works for :download:`this asymmetrical circle pattern <../../../acircles_pattern.png>` by setting the input width to 4 and height to 11. This time I've used a live camera feed by specifying its ID ("1") for the input. Here's, how a detected pattern should look: - -.. image:: images/asymetricalPattern.jpg - :alt: Asymmetrical circle detection - :align: center - -In both cases in the specified output XML/YAML file you'll find the camera and distortion coefficients matrices: - -.. code-block:: cpp - - - 3 - 3 -
d
- - 6.5746697944293521e+002 0. 3.1950000000000000e+002 0. - 6.5746697944293521e+002 2.3950000000000000e+002 0. 0. 1.
- - 5 - 1 -
d
- - -4.1802327176423804e-001 5.0715244063187526e-001 0. 0. - -5.7843597214487474e-001
- -Add these values as constants to your program, call the :imgproc_geometric:`initUndistortRectifyMap ` and the :imgproc_geometric:`remap ` function to remove distortion and enjoy distortion free inputs for cheap and low quality cameras. - -You may observe a runtime instance of this on the `YouTube here `_. - -.. raw:: html - -
- -
diff --git a/doc/tutorials/calib3d/camera_calibration_square_chess/camera_calibration_square_chess.rst b/doc/tutorials/calib3d/camera_calibration_square_chess/camera_calibration_square_chess.rst deleted file mode 100644 index 9a463f654d..0000000000 --- a/doc/tutorials/calib3d/camera_calibration_square_chess/camera_calibration_square_chess.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. _CameraCalibrationSquareChessBoardTutorial: - -Camera calibration with square chessboard -***************************************** - -.. highlight:: cpp - -The goal of this tutorial is to learn how to calibrate a camera given a set of chessboard images. - -*Test data*: use images in your data/chess folder. - -#. - Compile opencv with samples by setting ``BUILD_EXAMPLES`` to ``ON`` in cmake configuration. - -#. - Go to ``bin`` folder and use ``imagelist_creator`` to create an ``XML/YAML`` list of your images. - -#. - Then, run ``calibration`` sample to get camera parameters. Use square size equal to 3cm. - -Pose estimation -=============== - -Now, let us write a code that detects a chessboard in a new image and finds its distance from the camera. You can apply the same method to any object with known 3D geometry that you can detect in an image. - -*Test data*: use chess_test*.jpg images from your data folder. - -#. - Create an empty console project. Load a test image: :: - - Mat img = imread(argv[1], IMREAD_GRAYSCALE); - -#. - Detect a chessboard in this image using findChessboard function. :: - - bool found = findChessboardCorners( img, boardSize, ptvec, CALIB_CB_ADAPTIVE_THRESH ); - -#. - Now, write a function that generates a ``vector`` array of 3d coordinates of a chessboard in any coordinate system. For simplicity, let us choose a system such that one of the chessboard corners is in the origin and the board is in the plane *z = 0*. - -#. - Read camera parameters from XML/YAML file: :: - - FileStorage fs(filename, FileStorage::READ); - Mat intrinsics, distortion; - fs["camera_matrix"] >> intrinsics; - fs["distortion_coefficients"] >> distortion; - -#. - Now we are ready to find chessboard pose by running ``solvePnP``: :: - - vector boardPoints; - // fill the array - ... - - solvePnP(Mat(boardPoints), Mat(foundBoardCorners), cameraMatrix, - distCoeffs, rvec, tvec, false); - -#. - Calculate reprojection error like it is done in ``calibration`` sample (see ``opencv/samples/cpp/calibration.cpp``, function ``computeReprojectionErrors``). - -Question: how to calculate the distance from the camera origin to any of the corners? diff --git a/doc/tutorials/calib3d/table_of_content_calib3d/images/camera_calibration.png b/doc/tutorials/calib3d/images/camera_calibration.png similarity index 100% rename from doc/tutorials/calib3d/table_of_content_calib3d/images/camera_calibration.png rename to doc/tutorials/calib3d/images/camera_calibration.png diff --git a/doc/tutorials/calib3d/table_of_content_calib3d/images/camera_calibration_square_chess.jpg b/doc/tutorials/calib3d/images/camera_calibration_square_chess.jpg similarity index 100% rename from doc/tutorials/calib3d/table_of_content_calib3d/images/camera_calibration_square_chess.jpg rename to doc/tutorials/calib3d/images/camera_calibration_square_chess.jpg diff --git a/doc/tutorials/calib3d/table_of_content_calib3d/images/real_time_pose_estimation.jpg b/doc/tutorials/calib3d/images/real_time_pose_estimation.jpg similarity index 100% rename from doc/tutorials/calib3d/table_of_content_calib3d/images/real_time_pose_estimation.jpg rename to doc/tutorials/calib3d/images/real_time_pose_estimation.jpg diff --git a/doc/tutorials/calib3d/real_time_pose/real_time_pose.rst b/doc/tutorials/calib3d/real_time_pose/real_time_pose.rst deleted file mode 100644 index 9410418792..0000000000 --- a/doc/tutorials/calib3d/real_time_pose/real_time_pose.rst +++ /dev/null @@ -1,749 +0,0 @@ -.. _realTimePoseEstimation: - -Real Time pose estimation of a textured object -********************************************** - -Nowadays, augmented reality is one of the top research topic in computer vision and robotics fields. The most elemental problem in augmented reality is the estimation of the camera pose respect of an object in the case of computer vision area to do later some 3D rendering or in the case of robotics obtain an object pose in order to grasp it and do some manipulation. However, this is not a trivial problem to solve due to the fact that the most common issue in image processing is the computational cost of applying a lot of algorithms or mathematical operations for solving a problem which is basic and immediateley for humans. - - -Goal -==== - -In this tutorial is explained how to build a real time application to estimate the camera pose in order to track a textured object with six degrees of freedom given a 2D image and its 3D textured model. - -The application will have the followings parts: - -.. container:: enumeratevisibleitemswithsquare - - + Read 3D textured object model and object mesh. - + Take input from Camera or Video. - + Extract ORB features and descriptors from the scene. - + Match scene descriptors with model descriptors using Flann matcher. - + Pose estimation using PnP + Ransac. - + Linear Kalman Filter for bad poses rejection. - - -Theory -====== - -In computer vision estimate the camera pose from *n* 3D-to-2D point correspondences is a fundamental and well understood problem. The most general version of the problem requires estimating the six degrees of freedom of the pose and five calibration parameters: focal length, principal point, aspect ratio and skew. It could be established with a minimum of 6 correspondences, using the well known Direct Linear Transform (DLT) algorithm. There are, though, several simplifications to the problem which turn into an extensive list of different algorithms that improve the accuracy of the DLT. - -The most common simplification is to assume known calibration parameters which is the so-called Perspective-*n*-Point problem: - -.. image:: images/pnp.jpg - :alt: Perspective-n-Point problem scheme - :align: center - -**Problem Formulation:** Given a set of correspondences between 3D points :math:`p_i` expressed in a world reference frame, and their 2D projections :math:`u_i` onto the image, we seek to retrieve the pose (:math:`R` and :math:`t`) of the camera w.r.t. the world and the focal length :math:`f`. - -OpenCV provides four different approaches to solve the Perspective-*n*-Point problem which return :math:`R` and :math:`t`. Then, using the following formula it's possible to project 3D points into the image plane: - -.. math:: - - s\ \left [ \begin{matrix} u \\ v \\ 1 \end{matrix} \right ] = \left [ \begin{matrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix} \right ] \left [ \begin{matrix} r_{11} & r_{12} & r_{13} & t_1 \\ r_{21} & r_{22} & r_{23} & t_2 \\ r_{31} & r_{32} & r_{33} & t_3 \end{matrix} \right ] \left [ \begin{matrix} X \\ Y \\ Z\\ 1 \end{matrix} \right ] - -The complete documentation of how to manage with this equations is in :calib3d:`Camera Calibration and 3D Reconstruction <>`. - -Source code -=========== - -You can find the source code of this tutorial in the :file:`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/` folder of the OpenCV source library. - -The tutorial consists of two main programs: - -1. **Model registration** - - This applicaton is exclusive to whom don't have a 3D textured model of the object to be detected. You can use this program to create your own textured 3D model. This program only works for planar objects, then if you want to model an object with complex shape you should use a sophisticated software to create it. - - The application needs an input image of the object to be registered and its 3D mesh. We have also to provide the intrinsic parameters of the camera with which the input image was taken. All the files need to be specified using the absolute path or the relative one from your application’s working directory. If none files are specified the program will try to open the provided default parameters. - - The application starts up extracting the ORB features and descriptors from the input image and then uses the mesh along with the `Möller–Trumbore intersection algorithm `_ to compute the 3D coordinates of the found features. Finally, the 3D points and the descriptors are stored in different lists in a file with YAML format which each row is a different point. The technical background on how to store the files can be found in the :ref:`fileInputOutputXMLYAML` tutorial. - -.. image:: images/registration.png - :alt: Model registration - :align: center - - -2. **Model detection** - - The aim of this application is estimate in real time the object pose given its 3D textured model. - - The application starts up loading the 3D textured model in YAML file format with the same structure explained in the model registration program. From the scene, the ORB features and descriptors are detected and extracted. Then, is used :flann_based_matcher:`FlannBasedMatcher<>` with :flann:`LshIndexParams ` to do the matching between the scene descriptors and the model descriptors. Using the found matches along with :calib3d:`solvePnPRansac ` function the :math:`R` and :math:`t` of the camera are computed. Finally, a :video:`KalmanFilter` is applied in order to reject bad poses. - - In the case that you compiled OpenCV with the samples, you can find it in :file:`opencv/build/bin/cpp-tutorial-pnp_detection`. Then you can run the application and change some parameters: - - .. code-block:: cpp - - This program shows how to detect an object given its 3D textured model. You can choose to use a recorded video or the webcam. - Usage: - ./cpp-tutorial-pnp_detection -help - Keys: - 'esc' - to quit. - -------------------------------------------------------------------------- - - Usage: cpp-tutorial-pnp_detection [params] - - -c, --confidence (value:0.95) - RANSAC confidence - -e, --error (value:2.0) - RANSAC reprojection errror - -f, --fast (value:true) - use of robust fast match - -h, --help (value:true) - print this message - --in, --inliers (value:30) - minimum inliers for Kalman update - --it, --iterations (value:500) - RANSAC maximum iterations count - -k, --keypoints (value:2000) - number of keypoints to detect - --mesh - path to ply mesh - --method, --pnp (value:0) - PnP method: (0) ITERATIVE - (1) EPNP - (2) P3P - (3) DLS - --model - path to yml model - -r, --ratio (value:0.7) - threshold for ratio test - -v, --video - path to recorded video - - For example, you can run the application changing the pnp method: - - .. code-block:: cpp - - ./cpp-tutorial-pnp_detection --method=2 - - -Explanation -=========== - -Here is explained in detail the code for the real time application: - -1. **Read 3D textured object model and object mesh.** - - In order to load the textured model I implemented the *class* **Model** which has the function *load()* that opens a YAML file and take the stored 3D points with its corresponding descriptors. You can find an example of a 3D textured model in :file:`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/Data/cookies_ORB.yml`. - - .. code-block:: cpp - - /* Load a YAML file using OpenCV */ - void Model::load(const std::string path) - { - cv::Mat points3d_mat; - - cv::FileStorage storage(path, cv::FileStorage::READ); - storage["points_3d"] >> points3d_mat; - storage["descriptors"] >> descriptors_; - - points3d_mat.copyTo(list_points3d_in_); - - storage.release(); - - } - - In the main program the model is loaded as follows: - - .. code-block:: cpp - - Model model; // instantiate Model object - model.load(yml_read_path); // load a 3D textured object model - - In order to read the model mesh I implemented a *class* **Mesh** which has a function *load()* that opens a :math:`*`.ply file and store the 3D points of the object and also the composed triangles. You can find an example of a model mesh in :file:`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/Data/box.ply`. - - .. code-block:: cpp - - /* Load a CSV with *.ply format */ - void Mesh::load(const std::string path) - { - - // Create the reader - CsvReader csvReader(path); - - // Clear previous data - list_vertex_.clear(); - list_triangles_.clear(); - - // Read from .ply file - csvReader.readPLY(list_vertex_, list_triangles_); - - // Update mesh attributes - num_vertexs_ = list_vertex_.size(); - num_triangles_ = list_triangles_.size(); - - } - - In the main program the mesh is loaded as follows: - - .. code-block:: cpp - - Mesh mesh; // instantiate Mesh object - mesh.load(ply_read_path); // load an object mesh - - You can also load different model and mesh: - - .. code-block:: cpp - - ./cpp-tutorial-pnp_detection --mesh=/absolute_path_to_your_mesh.ply --model=/absolute_path_to_your_model.yml - - -2. **Take input from Camera or Video** - - To detect is necessary capture video. It's done loading a recorded video by passing the absolute path where it is located in your machine. In order to test the application you can find a recorded video in :file:`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/Data/box.mp4`. - - .. code-block:: cpp - - cv::VideoCapture cap; // instantiate VideoCapture - cap.open(video_read_path); // open a recorded video - - if(!cap.isOpened()) // check if we succeeded - { - std::cout << "Could not open the camera device" << std::endl; - return -1; - } - - Then the algorithm is computed frame per frame: - - .. code-block:: cpp - - cv::Mat frame, frame_vis; - - while(cap.read(frame) && cv::waitKey(30) != 27) // capture frame until ESC is pressed - { - - frame_vis = frame.clone(); // refresh visualisation frame - - // MAIN ALGORITHM - - } - - You can also load different recorded video: - - .. code-block:: cpp - - ./cpp-tutorial-pnp_detection --video=/absolute_path_to_your_video.mp4 - - -3. **Extract ORB features and descriptors from the scene** - - The next step is to detect the scene features and extract it descriptors. For this task I implemented a *class* **RobustMatcher** which has a function for keypoints detection and features extraction. You can find it in :file:`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/RobusMatcher.cpp`. In your *RobusMatch* object you can use any of the 2D features detectors of OpenCV. In this case I used :feature_detection_and_description:`ORB` features because is based on :feature_detection_and_description:`FAST` to detect the keypoints and :descriptor_extractor:`BRIEF` to extract the descriptors which means that is fast and robust to rotations. You can find more detailed information about *ORB* in the documentation. - - The following code is how to instantiate and set the features detector and the descriptors extractor: - - .. code-block:: cpp - - RobustMatcher rmatcher; // instantiate RobustMatcher - - cv::FeatureDetector * detector = new cv::OrbFeatureDetector(numKeyPoints); // instatiate ORB feature detector - cv::DescriptorExtractor * extractor = new cv::OrbDescriptorExtractor(); // instatiate ORB descriptor extractor - - rmatcher.setFeatureDetector(detector); // set feature detector - rmatcher.setDescriptorExtractor(extractor); // set descriptor extractor - - The features and descriptors will be computed by the *RobustMatcher* inside the matching function. - - -4. **Match scene descriptors with model descriptors using Flann matcher** - - It is the first step in our detection algorithm. The main idea is to match the scene descriptors with our model descriptors in order to know the 3D coordinates of the found features into the current scene. - - Firstly, we have to set which matcher we want to use. In this case is used :flann_based_matcher:`FlannBasedMatcher<>` matcher which in terms of computational cost is faster than the :brute_force_matcher:`BruteForceMatcher` matcher as we increase the trained collectction of features. Then, for FlannBased matcher the index created is *Multi-Probe LSH: Efficient Indexing for High-Dimensional Similarity Search* due to *ORB* descriptors are binary. - - You can tune the *LSH* and search parameters to improve the matching efficiency: - - .. code-block:: cpp - - cv::Ptr indexParams = cv::makePtr(6, 12, 1); // instantiate LSH index parameters - cv::Ptr searchParams = cv::makePtr(50); // instantiate flann search parameters - - cv::DescriptorMatcher * matcher = new cv::FlannBasedMatcher(indexParams, searchParams); // instantiate FlannBased matcher - rmatcher.setDescriptorMatcher(matcher); // set matcher - - - Secondly, we have to call the matcher by using *robustMatch()* or *fastRobustMatch()* function. The difference of using this two functions is its computational cost. The first method is slower but more robust at filtering good matches because uses two ratio test and a symmetry test. In contrast, the second method is faster but less robust because only applies a single ratio test to the matches. - - The following code is to get the model 3D points and its descriptors and then call the matcher in the main program: - - .. code-block:: cpp - - // Get the MODEL INFO - - std::vector list_points3d_model = model.get_points3d(); // list with model 3D coordinates - cv::Mat descriptors_model = model.get_descriptors(); // list with descriptors of each 3D coordinate - - .. code-block:: cpp - - // -- Step 1: Robust matching between model descriptors and scene descriptors - - std::vector good_matches; // to obtain the model 3D points in the scene - std::vector keypoints_scene; // to obtain the 2D points of the scene - - if(fast_match) - { - rmatcher.fastRobustMatch(frame, good_matches, keypoints_scene, descriptors_model); - } - else - { - rmatcher.robustMatch(frame, good_matches, keypoints_scene, descriptors_model); - } - - The following code corresponds to the *robustMatch()* function which belongs to the *RobustMatcher* class. This function uses the given image to detect the keypoints and extract the descriptors, match using *two Nearest Neighbour* the extracted descriptors with the given model descriptors and vice versa. Then, a ratio test is applied to the two direction matches in order to remove these matches which its distance ratio between the first and second best match is larger than a given threshold. Finally, a symmetry test is applied in order the remove non symmetrical matches. - - .. code-block:: cpp - - void RobustMatcher::robustMatch( const cv::Mat& frame, std::vector& good_matches, - std::vector& keypoints_frame, - const std::vector& keypoints_model, const cv::Mat& descriptors_model ) - { - - // 1a. Detection of the ORB features - this->computeKeyPoints(frame, keypoints_frame); - - // 1b. Extraction of the ORB descriptors - cv::Mat descriptors_frame; - this->computeDescriptors(frame, keypoints_frame, descriptors_frame); - - // 2. Match the two image descriptors - std::vector > matches12, matches21; - - // 2a. From image 1 to image 2 - matcher_->knnMatch(descriptors_frame, descriptors_model, matches12, 2); // return 2 nearest neighbours - - // 2b. From image 2 to image 1 - matcher_->knnMatch(descriptors_model, descriptors_frame, matches21, 2); // return 2 nearest neighbours - - // 3. Remove matches for which NN ratio is > than threshold - // clean image 1 -> image 2 matches - int removed1 = ratioTest(matches12); - // clean image 2 -> image 1 matches - int removed2 = ratioTest(matches21); - - // 4. Remove non-symmetrical matches - symmetryTest(matches12, matches21, good_matches); - - } - - After the matches filtering we have to subtract the 2D and 3D correspondences from the found scene keypoints and our 3D model using the obtained *DMatches* vector. For more information about :basicstructures:`DMatch ` check the documentation. - - .. code-block:: cpp - - // -- Step 2: Find out the 2D/3D correspondences - - std::vector list_points3d_model_match; // container for the model 3D coordinates found in the scene - std::vector list_points2d_scene_match; // container for the model 2D coordinates found in the scene - - for(unsigned int match_index = 0; match_index < good_matches.size(); ++match_index) - { - cv::Point3f point3d_model = list_points3d_model[ good_matches[match_index].trainIdx ]; // 3D point from model - cv::Point2f point2d_scene = keypoints_scene[ good_matches[match_index].queryIdx ].pt; // 2D point from the scene - list_points3d_model_match.push_back(point3d_model); // add 3D point - list_points2d_scene_match.push_back(point2d_scene); // add 2D point - } - - You can also change the ratio test threshold, the number of keypoints to detect as well as use or not the robust matcher: - - .. code-block:: cpp - - ./cpp-tutorial-pnp_detection --ratio=0.8 --keypoints=1000 --fast=false - - -5. **Pose estimation using PnP + Ransac** - - Once with the 2D and 3D correspondences we have to apply a PnP algorithm in order to estimate the camera pose. The reason why we have to use :calib3d:`solvePnPRansac ` instead of :calib3d:`solvePnP ` is due to the fact that after the matching not all the found correspondences are correct and, as like as not, there are false correspondences or also called *outliers*. The `Random Sample Consensus `_ or *Ransac* is a non-deterministic iterative method which estimate parameters of a mathematical model from observed data producing an aproximate result as the number of iterations increase. After appyling *Ransac* all the *outliers* will be eliminated to then estimate the camera pose with a certain probability to obtain a good solution. - - For the camera pose estimation I have implemented a *class* **PnPProblem**. This *class* has 4 atributes: a given calibration matrix, the rotation matrix, the translation matrix and the rotation-translation matrix. The intrinsic calibration parameters of the camera which you are using to estimate the pose are necessary. In order to obtain the parameters you can check :ref:`CameraCalibrationSquareChessBoardTutorial` and :ref:`cameraCalibrationOpenCV` tutorials. - - The following code is how to declare the *PnPProblem class* in the main program: - - .. code-block:: cpp - - // Intrinsic camera parameters: UVC WEBCAM - - double f = 55; // focal length in mm - double sx = 22.3, sy = 14.9; // sensor size - double width = 640, height = 480; // image size - - double params_WEBCAM[] = { width*f/sx, // fx - height*f/sy, // fy - width/2, // cx - height/2}; // cy - - PnPProblem pnp_detection(params_WEBCAM); // instantiate PnPProblem class - - The following code is how the *PnPProblem class* initialises its atributes: - - .. code-block:: cpp - - // Custom constructor given the intrinsic camera parameters - - PnPProblem::PnPProblem(const double params[]) - { - _A_matrix = cv::Mat::zeros(3, 3, CV_64FC1); // intrinsic camera parameters - _A_matrix.at(0, 0) = params[0]; // [ fx 0 cx ] - _A_matrix.at(1, 1) = params[1]; // [ 0 fy cy ] - _A_matrix.at(0, 2) = params[2]; // [ 0 0 1 ] - _A_matrix.at(1, 2) = params[3]; - _A_matrix.at(2, 2) = 1; - _R_matrix = cv::Mat::zeros(3, 3, CV_64FC1); // rotation matrix - _t_matrix = cv::Mat::zeros(3, 1, CV_64FC1); // translation matrix - _P_matrix = cv::Mat::zeros(3, 4, CV_64FC1); // rotation-translation matrix - - } - - OpenCV provides four PnP methods: ITERATIVE, EPNP, P3P and DLS. Depending on the application type, the estimation method will be different. In the case that we want to make a real time application, the more suitable methods are EPNP and P3P due to that are faster than ITERATIVE and DLS at finding an optimal solution. However, EPNP and P3P are not especially robust in front of planar surfaces and sometimes the pose estimation seems to have a mirror effect. Therefore, in this this tutorial is used ITERATIVE method due to the object to be detected has planar surfaces. - - The OpenCV Ransac implementation wants you to provide three parameters: the maximum number of iterations until stop the algorithm, the maximum allowed distance between the observed and computed point projections to consider it an inlier and the confidence to obtain a good result. You can tune these paramaters in order to improve your algorithm performance. Increasing the number of iterations you will have a more accurate solution, but will take more time to find a solution. Increasing the reprojection error will reduce the computation time, but your solution will be unaccurate. Decreasing the confidence your arlgorithm will be faster, but the obtained solution will be unaccurate. - - The following parameters work for this application: - - .. code-block:: cpp - - // RANSAC parameters - - int iterationsCount = 500; // number of Ransac iterations. - float reprojectionError = 2.0; // maximum allowed distance to consider it an inlier. - float confidence = 0.95; // ransac successful confidence. - - - The following code corresponds to the *estimatePoseRANSAC()* function which belongs to the *PnPProblem class*. This function estimates the rotation and translation matrix given a set of 2D/3D correspondences, the desired PnP method to use, the output inliers container and the Ransac parameters: - - .. code-block:: cpp - - // Estimate the pose given a list of 2D/3D correspondences with RANSAC and the method to use - - void PnPProblem::estimatePoseRANSAC( const std::vector &list_points3d, // list with model 3D coordinates - const std::vector &list_points2d, // list with scene 2D coordinates - int flags, cv::Mat &inliers, int iterationsCount, // PnP method; inliers container - float reprojectionError, float confidence ) // Ransac parameters - { - cv::Mat distCoeffs = cv::Mat::zeros(4, 1, CV_64FC1); // vector of distortion coefficients - cv::Mat rvec = cv::Mat::zeros(3, 1, CV_64FC1); // output rotation vector - cv::Mat tvec = cv::Mat::zeros(3, 1, CV_64FC1); // output translation vector - - bool useExtrinsicGuess = false; // if true the function uses the provided rvec and tvec values as - // initial approximations of the rotation and translation vectors - - cv::solvePnPRansac( list_points3d, list_points2d, _A_matrix, distCoeffs, rvec, tvec, - useExtrinsicGuess, iterationsCount, reprojectionError, confidence, - inliers, flags ); - - Rodrigues(rvec,_R_matrix); // converts Rotation Vector to Matrix - _t_matrix = tvec; // set translation matrix - - this->set_P_matrix(_R_matrix, _t_matrix); // set rotation-translation matrix - - } - - In the following code are the 3th and 4th steps of the main algorithm. The first, calling the above function and the second taking the output inliers vector from Ransac to get the 2D scene points for drawing purpose. As seen in the code we must be sure to apply Ransac if we have matches, in the other case, the function :calib3d:`solvePnPRansac ` crashes due to any OpenCV *bug*. - - .. code-block:: cpp - - if(good_matches.size() > 0) // None matches, then RANSAC crashes - { - - // -- Step 3: Estimate the pose using RANSAC approach - pnp_detection.estimatePoseRANSAC( list_points3d_model_match, list_points2d_scene_match, - pnpMethod, inliers_idx, iterationsCount, reprojectionError, confidence ); - - - // -- Step 4: Catch the inliers keypoints to draw - for(int inliers_index = 0; inliers_index < inliers_idx.rows; ++inliers_index) - { - int n = inliers_idx.at(inliers_index); // i-inlier - cv::Point2f point2d = list_points2d_scene_match[n]; // i-inlier point 2D - list_points2d_inliers.push_back(point2d); // add i-inlier to list - } - - - Finally, once the camera pose has been estimated we can use the :math:`R` and :math:`t` in order to compute the 2D projection onto the image of a given 3D point expressed in a world reference frame using the showed formula on *Theory*. - - The following code corresponds to the *backproject3DPoint()* function which belongs to the *PnPProblem class*. The function backproject a given 3D point expressed in a world reference frame onto a 2D image: - - .. code-block:: cpp - - // Backproject a 3D point to 2D using the estimated pose parameters - - cv::Point2f PnPProblem::backproject3DPoint(const cv::Point3f &point3d) - { - // 3D point vector [x y z 1]' - cv::Mat point3d_vec = cv::Mat(4, 1, CV_64FC1); - point3d_vec.at(0) = point3d.x; - point3d_vec.at(1) = point3d.y; - point3d_vec.at(2) = point3d.z; - point3d_vec.at(3) = 1; - - // 2D point vector [u v 1]' - cv::Mat point2d_vec = cv::Mat(4, 1, CV_64FC1); - point2d_vec = _A_matrix * _P_matrix * point3d_vec; - - // Normalization of [u v]' - cv::Point2f point2d; - point2d.x = point2d_vec.at(0) / point2d_vec.at(2); - point2d.y = point2d_vec.at(1) / point2d_vec.at(2); - - return point2d; - } - - The above function is used to compute all the 3D points of the object *Mesh* to show the pose of the object. - - You can also change RANSAC parameters and PnP method: - - .. code-block:: cpp - - ./cpp-tutorial-pnp_detection --error=0.25 --confidence=0.90 --iterations=250 --method=3 - - -6. **Linear Kalman Filter for bad poses rejection** - - Is it common in computer vision or robotics fields that after applying detection or tracking techniques, bad results are obtained due to some sensor errors. In order to avoid these bad detections in this tutorial is explained how to implement a Linear Kalman Filter. The Kalman Filter will be applied after detected a given number of inliers. - - You can find more information about what `Kalman Filter `_ is. In this tutorial it's used the OpenCV implementation of the :video:`Kalman Filter ` based on `Linear Kalman Filter for position and orientation tracking `_ to set the dynamics and measurement models. - - Firstly, we have to define our state vector which will have 18 states: the positional data (x,y,z) with its first and second derivatives (velocity and acceleration), then rotation is added in form of three euler angles (roll, pitch, jaw) together with their first and second derivatives (angular velocity and acceleration) - - .. math:: - - X = (x,y,z,\dot x,\dot y,\dot z,\ddot x,\ddot y,\ddot z,\psi,\theta,\phi,\dot \psi,\dot \theta,\dot \phi,\ddot \psi,\ddot \theta,\ddot \phi)^T - - Secondly, we have to define the number of measuremnts which will be 6: from :math:`R` and :math:`t` we can extract :math:`(x,y,z)` and :math:`(\psi,\theta,\phi)`. In addition, we have to define the number of control actions to apply to the system which in this case will be *zero*. Finally, we have to define the differential time between measurements which in this case is :math:`1/T`, where *T* is the frame rate of the video. - - .. code-block:: cpp - - cv::KalmanFilter KF; // instantiate Kalman Filter - - int nStates = 18; // the number of states - int nMeasurements = 6; // the number of measured states - int nInputs = 0; // the number of action control - - double dt = 0.125; // time between measurements (1/FPS) - - initKalmanFilter(KF, nStates, nMeasurements, nInputs, dt); // init function - - - The following code corresponds to the *Kalman Filter* initialisation. Firstly, is set the process noise, the measurement noise and the error covariance matrix. Secondly, are set the transition matrix which is the dynamic model and finally the measurement matrix, which is the measurement model. - - You can tune the process and measurement noise to improve the *Kalman Filter* performance. As the measurement noise is reduced the faster will converge doing the algorithm sensitive in front of bad measurements. - - .. code-block:: cpp - - void initKalmanFilter(cv::KalmanFilter &KF, int nStates, int nMeasurements, int nInputs, double dt) - { - - KF.init(nStates, nMeasurements, nInputs, CV_64F); // init Kalman Filter - - cv::setIdentity(KF.processNoiseCov, cv::Scalar::all(1e-5)); // set process noise - cv::setIdentity(KF.measurementNoiseCov, cv::Scalar::all(1e-4)); // set measurement noise - cv::setIdentity(KF.errorCovPost, cv::Scalar::all(1)); // error covariance - - - /* DYNAMIC MODEL */ - - // [1 0 0 dt 0 0 dt2 0 0 0 0 0 0 0 0 0 0 0] - // [0 1 0 0 dt 0 0 dt2 0 0 0 0 0 0 0 0 0 0] - // [0 0 1 0 0 dt 0 0 dt2 0 0 0 0 0 0 0 0 0] - // [0 0 0 1 0 0 dt 0 0 0 0 0 0 0 0 0 0 0] - // [0 0 0 0 1 0 0 dt 0 0 0 0 0 0 0 0 0 0] - // [0 0 0 0 0 1 0 0 dt 0 0 0 0 0 0 0 0 0] - // [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0] - // [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0] - // [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] - // [0 0 0 0 0 0 0 0 0 1 0 0 dt 0 0 dt2 0 0] - // [0 0 0 0 0 0 0 0 0 0 1 0 0 dt 0 0 dt2 0] - // [0 0 0 0 0 0 0 0 0 0 0 1 0 0 dt 0 0 dt2] - // [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 dt 0 0] - // [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 dt 0] - // [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 dt] - // [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0] - // [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0] - // [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1] - - // position - KF.transitionMatrix.at(0,3) = dt; - KF.transitionMatrix.at(1,4) = dt; - KF.transitionMatrix.at(2,5) = dt; - KF.transitionMatrix.at(3,6) = dt; - KF.transitionMatrix.at(4,7) = dt; - KF.transitionMatrix.at(5,8) = dt; - KF.transitionMatrix.at(0,6) = 0.5*pow(dt,2); - KF.transitionMatrix.at(1,7) = 0.5*pow(dt,2); - KF.transitionMatrix.at(2,8) = 0.5*pow(dt,2); - - // orientation - KF.transitionMatrix.at(9,12) = dt; - KF.transitionMatrix.at(10,13) = dt; - KF.transitionMatrix.at(11,14) = dt; - KF.transitionMatrix.at(12,15) = dt; - KF.transitionMatrix.at(13,16) = dt; - KF.transitionMatrix.at(14,17) = dt; - KF.transitionMatrix.at(9,15) = 0.5*pow(dt,2); - KF.transitionMatrix.at(10,16) = 0.5*pow(dt,2); - KF.transitionMatrix.at(11,17) = 0.5*pow(dt,2); - - - /* MEASUREMENT MODEL */ - - // [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - // [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - // [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] - // [0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0] - // [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] - // [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0] - - KF.measurementMatrix.at(0,0) = 1; // x - KF.measurementMatrix.at(1,1) = 1; // y - KF.measurementMatrix.at(2,2) = 1; // z - KF.measurementMatrix.at(3,9) = 1; // roll - KF.measurementMatrix.at(4,10) = 1; // pitch - KF.measurementMatrix.at(5,11) = 1; // yaw - - } - - In the following code is the 5th step of the main algorithm. When the obtained number of inliers after *Ransac* is over the threshold, the measurements matrix is filled and then the *Kalman Filter* is updated: - - .. code-block:: cpp - - // -- Step 5: Kalman Filter - - // GOOD MEASUREMENT - if( inliers_idx.rows >= minInliersKalman ) - { - - // Get the measured translation - cv::Mat translation_measured(3, 1, CV_64F); - translation_measured = pnp_detection.get_t_matrix(); - - // Get the measured rotation - cv::Mat rotation_measured(3, 3, CV_64F); - rotation_measured = pnp_detection.get_R_matrix(); - - // fill the measurements vector - fillMeasurements(measurements, translation_measured, rotation_measured); - - } - - // Instantiate estimated translation and rotation - cv::Mat translation_estimated(3, 1, CV_64F); - cv::Mat rotation_estimated(3, 3, CV_64F); - - // update the Kalman filter with good measurements - updateKalmanFilter( KF, measurements, - translation_estimated, rotation_estimated); - - The following code corresponds to the *fillMeasurements()* function which converts the measured `Rotation Matrix to Eulers angles `_ and fill the measurements matrix along with the measured translation vector: - - .. code-block:: cpp - - void fillMeasurements( cv::Mat &measurements, - const cv::Mat &translation_measured, const cv::Mat &rotation_measured) - { - // Convert rotation matrix to euler angles - cv::Mat measured_eulers(3, 1, CV_64F); - measured_eulers = rot2euler(rotation_measured); - - // Set measurement to predict - measurements.at(0) = translation_measured.at(0); // x - measurements.at(1) = translation_measured.at(1); // y - measurements.at(2) = translation_measured.at(2); // z - measurements.at(3) = measured_eulers.at(0); // roll - measurements.at(4) = measured_eulers.at(1); // pitch - measurements.at(5) = measured_eulers.at(2); // yaw - } - - - The following code corresponds to the *updateKalmanFilter()* function which update the Kalman Filter and set the estimated Rotation Matrix and translation vector. The estimated Rotation Matrix comes from the estimated `Euler angles to Rotation Matrix `_. - - .. code-block:: cpp - - void updateKalmanFilter( cv::KalmanFilter &KF, cv::Mat &measurement, - cv::Mat &translation_estimated, cv::Mat &rotation_estimated ) - { - - // First predict, to update the internal statePre variable - cv::Mat prediction = KF.predict(); - - // The "correct" phase that is going to use the predicted value and our measurement - cv::Mat estimated = KF.correct(measurement); - - // Estimated translation - translation_estimated.at(0) = estimated.at(0); - translation_estimated.at(1) = estimated.at(1); - translation_estimated.at(2) = estimated.at(2); - - // Estimated euler angles - cv::Mat eulers_estimated(3, 1, CV_64F); - eulers_estimated.at(0) = estimated.at(9); - eulers_estimated.at(1) = estimated.at(10); - eulers_estimated.at(2) = estimated.at(11); - - // Convert estimated quaternion to rotation matrix - rotation_estimated = euler2rot(eulers_estimated); - - } - - The 6th step is set the estimated rotation-translation matrix: - - .. code-block:: cpp - - // -- Step 6: Set estimated projection matrix - pnp_detection_est.set_P_matrix(rotation_estimated, translation_estimated); - - - The last and optional step is draw the found pose. To do it I implemented a function to draw all the mesh 3D points and an extra reference axis: - - .. code-block:: cpp - - // -- Step X: Draw pose - - drawObjectMesh(frame_vis, &mesh, &pnp_detection, green); // draw current pose - drawObjectMesh(frame_vis, &mesh, &pnp_detection_est, yellow); // draw estimated pose - - double l = 5; - std::vector pose_points2d; - pose_points2d.push_back(pnp_detection_est.backproject3DPoint(cv::Point3f(0,0,0))); // axis center - pose_points2d.push_back(pnp_detection_est.backproject3DPoint(cv::Point3f(l,0,0))); // axis x - pose_points2d.push_back(pnp_detection_est.backproject3DPoint(cv::Point3f(0,l,0))); // axis y - pose_points2d.push_back(pnp_detection_est.backproject3DPoint(cv::Point3f(0,0,l))); // axis z - draw3DCoordinateAxes(frame_vis, pose_points2d); // draw axes - - You can also modify the minimum inliers to update Kalman Filter: - - .. code-block:: cpp - - ./cpp-tutorial-pnp_detection --inliers=20 - - -Results -======= - -The following videos are the results of pose estimation in real time using the explained detection algorithm using the following parameters: - - .. code-block:: cpp - - // Robust Matcher parameters - - int numKeyPoints = 2000; // number of detected keypoints - float ratio = 0.70f; // ratio test - bool fast_match = true; // fastRobustMatch() or robustMatch() - - - // RANSAC parameters - - int iterationsCount = 500; // number of Ransac iterations. - int reprojectionError = 2.0; // maximum allowed distance to consider it an inlier. - float confidence = 0.95; // ransac successful confidence. - - - // Kalman Filter parameters - - int minInliersKalman = 30; // Kalman threshold updating - - -You can watch the real time pose estimation on the `YouTube here `_. - -.. raw:: html - -
- -
-
- -
diff --git a/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.markdown b/doc/tutorials/calib3d/table_of_content_calib3d.markdown similarity index 100% rename from doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.markdown rename to doc/tutorials/calib3d/table_of_content_calib3d.markdown diff --git a/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.rst b/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.rst deleted file mode 100644 index 47c03d1679..0000000000 --- a/doc/tutorials/calib3d/table_of_content_calib3d/table_of_content_calib3d.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. _Table-Of-Content-Calib3D: - -*calib3d* module. Camera calibration and 3D reconstruction ------------------------------------------------------------ - -Although we got most of our images in a 2D format they do come from a 3D world. Here you will learn how to find out from the 2D images information about the 3D world. - -.. include:: ../../definitions/tocDefinitions.rst - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |CameraCalSqChess| **Title:** :ref:`CameraCalibrationSquareChessBoardTutorial` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_VictorE| - - You will use some chessboard images to calibrate your camera. - - ===================== ============================================== - - .. |CameraCalSqChess| image:: images/camera_calibration_square_chess.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |CameraCalibration| **Title:** :ref:`cameraCalibrationOpenCV` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - Camera calibration by using either the chessboard, circle or the asymmetrical circle pattern. Get the images either from a camera attached, a video file or from an image collection. - - ===================== ============================================== - - .. |CameraCalibration| image:: images/camera_calibration.png - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |PoseEstimation| **Title:** :ref:`realTimePoseEstimation` - - *Compatibility:* > OpenCV 2.0 - - *Author:* Edgar Riba - - Real time pose estimation of a textured object using ORB features, FlannBased matcher, PnP approach plus Ransac and Linear Kalman Filter to reject possible bad poses. - - ===================== ============================================== - - .. |PoseEstimation| image:: images/real_time_pose_estimation.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. toctree:: - :hidden: - - ../camera_calibration_square_chess/camera_calibration_square_chess - ../camera_calibration/camera_calibration - ../real_time_pose/real_time_pose diff --git a/doc/tutorials/core/adding_images/adding_images.rst b/doc/tutorials/core/adding_images/adding_images.rst deleted file mode 100644 index 922f6918b0..0000000000 --- a/doc/tutorials/core/adding_images/adding_images.rst +++ /dev/null @@ -1,120 +0,0 @@ -.. _Adding_Images: - -Adding (blending) two images using OpenCV -******************************************* - -Goal -===== - -In this tutorial you will learn: - -.. container:: enumeratevisibleitemswithsquare - - * what is *linear blending* and why it is useful; - * how to add two images using :add_weighted:`addWeighted <>` - -Theory -======= - -.. note:: - - The explanation below belongs to the book `Computer Vision: Algorithms and Applications `_ by Richard Szeliski - -From our previous tutorial, we know already a bit of *Pixel operators*. An interesting dyadic (two-input) operator is the *linear blend operator*: - -.. math:: - - g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x) - -By varying :math:`\alpha` from :math:`0 \rightarrow 1` this operator can be used to perform a temporal *cross-disolve* between two images or videos, as seen in slide shows and film productions (cool, eh?) - -Code -===== - -As usual, after the not-so-lengthy explanation, let's go to the code: - -.. code-block:: cpp - - #include - #include - - using namespace cv; - - int main( int argc, char** argv ) - { - double alpha = 0.5; double beta; double input; - - Mat src1, src2, dst; - - /// Ask the user enter alpha - std::cout<<" Simple Linear Blender "<>input; - - /// We use the alpha provided by the user if it is between 0 and 1 - if( input >= 0.0 && input <= 1.0 ) - { alpha = input; } - - /// Read image ( same size, same type ) - src1 = imread("../../images/LinuxLogo.jpg"); - src2 = imread("../../images/WindowsLogo.jpg"); - - if( !src1.data ) { printf("Error loading src1 \n"); return -1; } - if( !src2.data ) { printf("Error loading src2 \n"); return -1; } - - /// Create Windows - namedWindow("Linear Blend", 1); - - beta = ( 1.0 - alpha ); - addWeighted( src1, alpha, src2, beta, 0.0, dst); - - imshow( "Linear Blend", dst ); - - waitKey(0); - return 0; - } - -Explanation -============ - -#. Since we are going to perform: - - .. math:: - - g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x) - - We need two source images (:math:`f_{0}(x)` and :math:`f_{1}(x)`). So, we load them in the usual way: - - .. code-block:: cpp - - src1 = imread("../../images/LinuxLogo.jpg"); - src2 = imread("../../images/WindowsLogo.jpg"); - - .. warning:: - - Since we are *adding* *src1* and *src2*, they both have to be of the same size (width and height) and type. - -#. Now we need to generate the :math:`g(x)` image. For this, the function :add_weighted:`addWeighted <>` comes quite handy: - - .. code-block:: cpp - - beta = ( 1.0 - alpha ); - addWeighted( src1, alpha, src2, beta, 0.0, dst); - - since :add_weighted:`addWeighted <>` produces: - - .. math:: - - dst = \alpha \cdot src1 + \beta \cdot src2 + \gamma - - In this case, :math:`\gamma` is the argument :math:`0.0` in the code above. - -#. Create windows, show the images and wait for the user to end the program. - -Result -======= - -.. image:: images/Adding_Images_Tutorial_Result_Big.jpg - :alt: Blending Images Tutorial - Final Result - :align: center diff --git a/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.rst b/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.rst deleted file mode 100644 index 7d40e016bb..0000000000 --- a/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.rst +++ /dev/null @@ -1,277 +0,0 @@ -.. _Drawing_1: - -Basic Drawing -**************** - -Goals -====== -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use :point:`Point <>` to define 2D points in an image. - * Use :scalar:`Scalar <>` and why it is useful - * Draw a **line** by using the OpenCV function :line:`line <>` - * Draw an **ellipse** by using the OpenCV function :ellipse:`ellipse <>` - * Draw a **rectangle** by using the OpenCV function :rectangle:`rectangle <>` - * Draw a **circle** by using the OpenCV function :circle:`circle <>` - * Draw a **filled polygon** by using the OpenCV function :fill_poly:`fillPoly <>` - -OpenCV Theory -=============== - -For this tutorial, we will heavily use two structures: :point:`Point <>` and :scalar:`Scalar <>`: - -Point -------- - -.. container:: enumeratevisibleitemswithsquare - - It represents a 2D point, specified by its image coordinates :math:`x` and :math:`y`. We can define it as: - -.. code-block:: cpp - - Point pt; - pt.x = 10; - pt.y = 8; - -or - -.. code-block:: cpp - - Point pt = Point(10, 8); - -Scalar -------- -* Represents a 4-element vector. The type Scalar is widely used in OpenCV for passing pixel values. -* In this tutorial, we will use it extensively to represent RGB color values (3 parameters). It is not necessary to define the last argument if it is not going to be used. -* Let's see an example, if we are asked for a color argument and we give: - - .. code-block:: cpp - - Scalar( a, b, c ) - - We would be defining a RGB color such as: *Red = c*, *Green = b* and *Blue = a* - - -Code -===== -* This code is in your OpenCV sample folder. Otherwise you can grab it from `here `_ - -Explanation -============= - -#. Since we plan to draw two examples (an atom and a rook), we have to create 02 images and two windows to display them. - - .. code-block:: cpp - - /// Windows names - char atom_window[] = "Drawing 1: Atom"; - char rook_window[] = "Drawing 2: Rook"; - - /// Create black empty images - Mat atom_image = Mat::zeros( w, w, CV_8UC3 ); - Mat rook_image = Mat::zeros( w, w, CV_8UC3 ); - -#. We created functions to draw different geometric shapes. For instance, to draw the atom we used *MyEllipse* and *MyFilledCircle*: - - .. code-block:: cpp - - /// 1. Draw a simple atom: - - /// 1.a. Creating ellipses - MyEllipse( atom_image, 90 ); - MyEllipse( atom_image, 0 ); - MyEllipse( atom_image, 45 ); - MyEllipse( atom_image, -45 ); - - /// 1.b. Creating circles - MyFilledCircle( atom_image, Point( w/2.0, w/2.0) ); - -#. And to draw the rook we employed *MyLine*, *rectangle* and a *MyPolygon*: - - .. code-block:: cpp - - /// 2. Draw a rook - - /// 2.a. Create a convex polygon - MyPolygon( rook_image ); - - /// 2.b. Creating rectangles - rectangle( rook_image, - Point( 0, 7*w/8.0 ), - Point( w, w), - Scalar( 0, 255, 255 ), - -1, - 8 ); - - /// 2.c. Create a few lines - MyLine( rook_image, Point( 0, 15*w/16 ), Point( w, 15*w/16 ) ); - MyLine( rook_image, Point( w/4, 7*w/8 ), Point( w/4, w ) ); - MyLine( rook_image, Point( w/2, 7*w/8 ), Point( w/2, w ) ); - MyLine( rook_image, Point( 3*w/4, 7*w/8 ), Point( 3*w/4, w ) ); - -#. Let's check what is inside each of these functions: - - * *MyLine* - - .. code-block:: cpp - - void MyLine( Mat img, Point start, Point end ) - { - int thickness = 2; - int lineType = 8; - line( img, start, end, - Scalar( 0, 0, 0 ), - thickness, - lineType ); - } - - As we can see, *MyLine* just call the function :line:`line <>`, which does the following: - - .. container:: enumeratevisibleitemswithsquare - - * Draw a line from Point **start** to Point **end** - * The line is displayed in the image **img** - * The line color is defined by **Scalar( 0, 0, 0)** which is the RGB value correspondent to **Black** - * The line thickness is set to **thickness** (in this case 2) - * The line is a 8-connected one (**lineType** = 8) - - * *MyEllipse* - - .. code-block:: cpp - - void MyEllipse( Mat img, double angle ) - { - int thickness = 2; - int lineType = 8; - - ellipse( img, - Point( w/2.0, w/2.0 ), - Size( w/4.0, w/16.0 ), - angle, - 0, - 360, - Scalar( 255, 0, 0 ), - thickness, - lineType ); - } - - From the code above, we can observe that the function :ellipse:`ellipse <>` draws an ellipse such that: - - .. container:: enumeratevisibleitemswithsquare - - * The ellipse is displayed in the image **img** - * The ellipse center is located in the point **(w/2.0, w/2.0)** and is enclosed in a box of size **(w/4.0, w/16.0)** - * The ellipse is rotated **angle** degrees - * The ellipse extends an arc between **0** and **360** degrees - * The color of the figure will be **Scalar( 255, 255, 0)** which means blue in RGB value. - * The ellipse's **thickness** is 2. - - - * *MyFilledCircle* - - .. code-block:: cpp - - void MyFilledCircle( Mat img, Point center ) - { - int thickness = -1; - int lineType = 8; - - circle( img, - center, - w/32.0, - Scalar( 0, 0, 255 ), - thickness, - lineType ); - } - - Similar to the ellipse function, we can observe that *circle* receives as arguments: - - .. container:: enumeratevisibleitemswithsquare - - * The image where the circle will be displayed (**img**) - * The center of the circle denoted as the Point **center** - * The radius of the circle: **w/32.0** - * The color of the circle: **Scalar(0, 0, 255)** which means *Red* in BGR - * Since **thickness** = -1, the circle will be drawn filled. - - * *MyPolygon* - - .. code-block:: cpp - - void MyPolygon( Mat img ) - { - int lineType = 8; - - /* Create some points */ - Point rook_points[1][20]; - rook_points[0][0] = Point( w/4.0, 7*w/8.0 ); - rook_points[0][1] = Point( 3*w/4.0, 7*w/8.0 ); - rook_points[0][2] = Point( 3*w/4.0, 13*w/16.0 ); - rook_points[0][3] = Point( 11*w/16.0, 13*w/16.0 ); - rook_points[0][4] = Point( 19*w/32.0, 3*w/8.0 ); - rook_points[0][5] = Point( 3*w/4.0, 3*w/8.0 ); - rook_points[0][6] = Point( 3*w/4.0, w/8.0 ); - rook_points[0][7] = Point( 26*w/40.0, w/8.0 ); - rook_points[0][8] = Point( 26*w/40.0, w/4.0 ); - rook_points[0][9] = Point( 22*w/40.0, w/4.0 ); - rook_points[0][10] = Point( 22*w/40.0, w/8.0 ); - rook_points[0][11] = Point( 18*w/40.0, w/8.0 ); - rook_points[0][12] = Point( 18*w/40.0, w/4.0 ); - rook_points[0][13] = Point( 14*w/40.0, w/4.0 ); - rook_points[0][14] = Point( 14*w/40.0, w/8.0 ); - rook_points[0][15] = Point( w/4.0, w/8.0 ); - rook_points[0][16] = Point( w/4.0, 3*w/8.0 ); - rook_points[0][17] = Point( 13*w/32.0, 3*w/8.0 ); - rook_points[0][18] = Point( 5*w/16.0, 13*w/16.0 ); - rook_points[0][19] = Point( w/4.0, 13*w/16.0) ; - - const Point* ppt[1] = { rook_points[0] }; - int npt[] = { 20 }; - - fillPoly( img, - ppt, - npt, - 1, - Scalar( 255, 255, 255 ), - lineType ); - } - - To draw a filled polygon we use the function :fill_poly:`fillPoly <>`. We note that: - - .. container:: enumeratevisibleitemswithsquare - - * The polygon will be drawn on **img** - * The vertices of the polygon are the set of points in **ppt** - * The total number of vertices to be drawn are **npt** - * The number of polygons to be drawn is only **1** - * The color of the polygon is defined by **Scalar( 255, 255, 255)**, which is the BGR value for *white* - - * *rectangle* - - .. code-block:: cpp - - rectangle( rook_image, - Point( 0, 7*w/8.0 ), - Point( w, w), - Scalar( 0, 255, 255 ), - -1, 8 ); - - Finally we have the :rectangle:`rectangle <>` function (we did not create a special function for this guy). We note that: - - .. container:: enumeratevisibleitemswithsquare - - * The rectangle will be drawn on **rook_image** - * Two opposite vertices of the rectangle are defined by ** Point( 0, 7*w/8.0 )** and **Point( w, w)** - * The color of the rectangle is given by **Scalar(0, 255, 255)** which is the BGR value for *yellow* - * Since the thickness value is given by **-1**, the rectangle will be filled. - -Result -======= - -Compiling and running your program should give you a result like this: - -.. image:: images/Drawing_1_Tutorial_Result_0.png - :alt: Drawing Tutorial 1 - Final Result - :align: center diff --git a/doc/tutorials/core/basic_linear_transform/basic_linear_transform.rst b/doc/tutorials/core/basic_linear_transform/basic_linear_transform.rst deleted file mode 100644 index 6c9434a260..0000000000 --- a/doc/tutorials/core/basic_linear_transform/basic_linear_transform.rst +++ /dev/null @@ -1,209 +0,0 @@ -.. _Basic_Linear_Transform: - -Changing the contrast and brightness of an image! -*************************************************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - + Access pixel values - + Initialize a matrix with zeros - + Learn what :saturate_cast:`saturate_cast <>` does and why it is useful - + Get some cool info about pixel transformations - -Theory -======= - -.. note:: - - The explanation below belongs to the book `Computer Vision: Algorithms and Applications `_ by Richard Szeliski - -Image Processing --------------------- - -.. container:: enumeratevisibleitemswithsquare - - * A general image processing operator is a function that takes one or more input images and produces an output image. - - * Image transforms can be seen as: - - + Point operators (pixel transforms) - + Neighborhood (area-based) operators - - -Pixel Transforms ------------------ - -.. container:: enumeratevisibleitemswithsquare - - * In this kind of image processing transform, each output pixel's value depends on only the corresponding input pixel value (plus, potentially, some globally collected information or parameters). - - * Examples of such operators include *brightness and contrast adjustments* as well as color correction and transformations. - -Brightness and contrast adjustments ------------------------------------- - -.. container:: enumeratevisibleitemswithsquare - - * Two commonly used point processes are *multiplication* and *addition* with a constant: - - .. math:: - - g(x) = \alpha f(x) + \beta - - * The parameters :math:`\alpha > 0` and :math:`\beta` are often called the *gain* and *bias* parameters; sometimes these parameters are said to control *contrast* and *brightness* respectively. - - * You can think of :math:`f(x)` as the source image pixels and :math:`g(x)` as the output image pixels. Then, more conveniently we can write the expression as: - - .. math:: - - g(i,j) = \alpha \cdot f(i,j) + \beta - - where :math:`i` and :math:`j` indicates that the pixel is located in the *i-th* row and *j-th* column. - -Code -===== - -* The following code performs the operation :math:`g(i,j) = \alpha \cdot f(i,j) + \beta` : - -.. code-block:: cpp - - #include - #include - - using namespace cv; - - double alpha; /*< Simple contrast control */ - int beta; /*< Simple brightness control */ - - int main( int argc, char** argv ) - { - /// Read image given by user - Mat image = imread( argv[1] ); - Mat new_image = Mat::zeros( image.size(), image.type() ); - - /// Initialize values - std::cout<<" Basic Linear Transforms "<>alpha; - std::cout<<"* Enter the beta value [0-100]: "; std::cin>>beta; - - /// Do the operation new_image(i,j) = alpha*image(i,j) + beta - for( int y = 0; y < image.rows; y++ ) { - for( int x = 0; x < image.cols; x++ ) { - for( int c = 0; c < 3; c++ ) { - new_image.at(y,x)[c] = - saturate_cast( alpha*( image.at(y,x)[c] ) + beta ); - } - } - } - - /// Create Windows - namedWindow("Original Image", 1); - namedWindow("New Image", 1); - - /// Show stuff - imshow("Original Image", image); - imshow("New Image", new_image); - - /// Wait until user press some key - waitKey(); - return 0; - } - -Explanation -============ - -#. We begin by creating parameters to save :math:`\alpha` and :math:`\beta` to be entered by the user: - - .. code-block:: cpp - - double alpha; - int beta; - - -#. We load an image using :imread:`imread <>` and save it in a Mat object: - - .. code-block:: cpp - - Mat image = imread( argv[1] ); - -#. Now, since we will make some transformations to this image, we need a new Mat object to store it. Also, we want this to have the following features: - - .. container:: enumeratevisibleitemswithsquare - - * Initial pixel values equal to zero - * Same size and type as the original image - - .. code-block:: cpp - - Mat new_image = Mat::zeros( image.size(), image.type() ); - - We observe that :mat_zeros:`Mat::zeros <>` returns a Matlab-style zero initializer based on *image.size()* and *image.type()* - -#. Now, to perform the operation :math:`g(i,j) = \alpha \cdot f(i,j) + \beta` we will access to each pixel in image. Since we are operating with RGB images, we will have three values per pixel (R, G and B), so we will also access them separately. Here is the piece of code: - - .. code-block:: cpp - - for( int y = 0; y < image.rows; y++ ) { - for( int x = 0; x < image.cols; x++ ) { - for( int c = 0; c < 3; c++ ) { - new_image.at(y,x)[c] = - saturate_cast( alpha*( image.at(y,x)[c] ) + beta ); - } - } - } - - Notice the following: - - .. container:: enumeratevisibleitemswithsquare - - * To access each pixel in the images we are using this syntax: *image.at(y,x)[c]* where *y* is the row, *x* is the column and *c* is R, G or B (0, 1 or 2). - - * Since the operation :math:`\alpha \cdot p(i,j) + \beta` can give values out of range or not integers (if :math:`\alpha` is float), we use :saturate_cast:`saturate_cast <>` to make sure the values are valid. - - -#. Finally, we create windows and show the images, the usual way. - - .. code-block:: cpp - - namedWindow("Original Image", 1); - namedWindow("New Image", 1); - - imshow("Original Image", image); - imshow("New Image", new_image); - - waitKey(0); - -.. note:: - - Instead of using the **for** loops to access each pixel, we could have simply used this command: - - .. code-block:: cpp - - image.convertTo(new_image, -1, alpha, beta); - - where :convert_to:`convertTo <>` would effectively perform *new_image = a*image + beta*. However, we wanted to show you how to access each pixel. In any case, both methods give the same result but convertTo is more optimized and works a lot faster. - -Result -======= - -* Running our code and using :math:`\alpha = 2.2` and :math:`\beta = 50` - - .. code-block:: bash - - $ ./BasicLinearTransforms lena.jpg - Basic Linear Transforms - ------------------------- - * Enter the alpha value [1.0-3.0]: 2.2 - * Enter the beta value [0-100]: 50 - -* We get this: - - .. image:: images/Basic_Linear_Transform_Tutorial_Result_big.jpg - :alt: Basic Linear Transform - Final Result - :align: center diff --git a/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.markdown b/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.markdown index f4c9b87af7..1e2d5203ce 100644 --- a/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.markdown +++ b/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.markdown @@ -15,21 +15,14 @@ Source code ----------- You can [download this from here -](samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp) or +](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp) or find it in the `samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp` of the OpenCV source code library. Here's a sample usage of @ref cv::dft() : -@dontinclude cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp -@until highgui.hpp -@skipline iostream -@skip main -@until { -@skip filename -@until return 0; -@until } +@includelineno cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp Explanation ----------- @@ -147,7 +140,7 @@ An application idea would be to determine the geometrical orientation present in example, let us find out if a text is horizontal or not? Looking at some text you'll notice that the text lines sort of form also horizontal lines and the letters form sort of vertical lines. These two main components of a text snippet may be also seen in case of the Fourier transform. Let us use -[this horizontal ](samples/data/imageTextN.png) and [this rotated](samples/data/imageTextR.png) +[this horizontal ](https://github.com/Itseez/opencv/tree/master/samples/data/imageTextN.png) and [this rotated](https://github.com/Itseez/opencv/tree/master/samples/data/imageTextR.png) image about a text. In case of the horizontal text: diff --git a/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.rst b/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.rst deleted file mode 100644 index 8c41e6520c..0000000000 --- a/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.rst +++ /dev/null @@ -1,143 +0,0 @@ -.. _discretFourierTransform: - -Discrete Fourier Transform -************************** - -Goal -==== - -We'll seek answers for the following questions: - -.. container:: enumeratevisibleitemswithsquare - - + What is a Fourier transform and why use it? - + How to do it in OpenCV? - + Usage of functions such as: :imgprocfilter:`copyMakeBorder() `, :operationsonarrays:`merge() `, :operationsonarrays:`dft() `, :operationsonarrays:`getOptimalDFTSize() `, :operationsonarrays:`log() ` and :operationsonarrays:`normalize() ` . - -Source code -=========== - -You can :download:`download this from here <../../../../samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp>` or find it in the :file:`samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp` of the OpenCV source code library. - -Here's a sample usage of :operationsonarrays:`dft() ` : - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 1-4, 6, 20-21, 24-79 - -Explanation -=========== - -The Fourier Transform will decompose an image into its sinus and cosines components. In other words, it will transform an image from its spatial domain to its frequency domain. The idea is that any function may be approximated exactly with the sum of infinite sinus and cosines functions. The Fourier Transform is a way how to do this. Mathematically a two dimensional images Fourier transform is: - -.. math:: - - F(k,l) = \displaystyle\sum\limits_{i=0}^{N-1}\sum\limits_{j=0}^{N-1} f(i,j)e^{-i2\pi(\frac{ki}{N}+\frac{lj}{N})} - - e^{ix} = \cos{x} + i\sin {x} - -Here f is the image value in its spatial domain and F in its frequency domain. The result of the transformation is complex numbers. Displaying this is possible either via a *real* image and a *complex* image or via a *magnitude* and a *phase* image. However, throughout the image processing algorithms only the *magnitude* image is interesting as this contains all the information we need about the images geometric structure. Nevertheless, if you intend to make some modifications of the image in these forms and then you need to retransform it you'll need to preserve both of these. - -In this sample I'll show how to calculate and show the *magnitude* image of a Fourier Transform. In case of digital images are discrete. This means they may take up a value from a given domain value. For example in a basic gray scale image values usually are between zero and 255. Therefore the Fourier Transform too needs to be of a discrete type resulting in a Discrete Fourier Transform (*DFT*). You'll want to use this whenever you need to determine the structure of an image from a geometrical point of view. Here are the steps to follow (in case of a gray scale input image *I*): - -1. **Expand the image to an optimal size**. The performance of a DFT is dependent of the image size. It tends to be the fastest for image sizes that are multiple of the numbers two, three and five. Therefore, to achieve maximal performance it is generally a good idea to pad border values to the image to get a size with such traits. The :operationsonarrays:`getOptimalDFTSize() ` returns this optimal size and we can use the :imgprocfilter:`copyMakeBorder() ` function to expand the borders of an image: - - .. code-block:: cpp - - Mat padded; //expand input image to optimal size - int m = getOptimalDFTSize( I.rows ); - int n = getOptimalDFTSize( I.cols ); // on the border add zero pixels - copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0)); - - The appended pixels are initialized with zero. - -2. **Make place for both the complex and the real values**. The result of a Fourier Transform is complex. This implies that for each image value the result is two image values (one per component). Moreover, the frequency domains range is much larger than its spatial counterpart. Therefore, we store these usually at least in a *float* format. Therefore we'll convert our input image to this type and expand it with another channel to hold the complex values: - - .. code-block:: cpp - - Mat planes[] = {Mat_(padded), Mat::zeros(padded.size(), CV_32F)}; - Mat complexI; - merge(planes, 2, complexI); // Add to the expanded another plane with zeros - -3. **Make the Discrete Fourier Transform**. It's possible an in-place calculation (same input as output): - - .. code-block:: cpp - - dft(complexI, complexI); // this way the result may fit in the source matrix - -4. **Transform the real and complex values to magnitude**. A complex number has a real (*Re*) and a complex (imaginary - *Im*) part. The results of a DFT are complex numbers. The magnitude of a DFT is: - - .. math:: - - M = \sqrt[2]{ {Re(DFT(I))}^2 + {Im(DFT(I))}^2} - - Translated to OpenCV code: - - .. code-block:: cpp - - split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) - magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude - Mat magI = planes[0]; - -5. **Switch to a logarithmic scale**. It turns out that the dynamic range of the Fourier coefficients is too large to be displayed on the screen. We have some small and some high changing values that we can't observe like this. Therefore the high values will all turn out as white points, while the small ones as black. To use the gray scale values to for visualization we can transform our linear scale to a logarithmic one: - - .. math:: - - M_1 = \log{(1 + M)} - - Translated to OpenCV code: - - .. code-block:: cpp - - magI += Scalar::all(1); // switch to logarithmic scale - log(magI, magI); - -6. **Crop and rearrange**. Remember, that at the first step, we expanded the image? Well, it's time to throw away the newly introduced values. For visualization purposes we may also rearrange the quadrants of the result, so that the origin (zero, zero) corresponds with the image center. - - .. code-block:: cpp - - magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); - int cx = magI.cols/2; - int cy = magI.rows/2; - - Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant - Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right - Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left - Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right - - Mat tmp; // swap quadrants (Top-Left with Bottom-Right) - q0.copyTo(tmp); - q3.copyTo(q0); - tmp.copyTo(q3); - - q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left) - q2.copyTo(q1); - tmp.copyTo(q2); - -7. **Normalize**. This is done again for visualization purposes. We now have the magnitudes, however this are still out of our image display range of zero to one. We normalize our values to this range using the :operationsonarrays:`normalize() ` function. - - .. code-block:: cpp - - normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a - // viewable image form (float between values 0 and 1). - -Result -====== - -An application idea would be to determine the geometrical orientation present in the image. For example, let us find out if a text is horizontal or not? Looking at some text you'll notice that the text lines sort of form also horizontal lines and the letters form sort of vertical lines. These two main components of a text snippet may be also seen in case of the Fourier transform. Let us use :download:`this horizontal <../../../../samples/data/imageTextN.png>` and :download:`this rotated<../../../../samples/data/imageTextR.png>` image about a text. - -In case of the horizontal text: - -.. image:: images/result_normal.jpg - :alt: In case of normal text - :align: center - -In case of a rotated text: - -.. image:: images/result_rotated.jpg - :alt: In case of rotated text - :align: center - -You can see that the most influential components of the frequency domain (brightest dots on the magnitude image) follow the geometric rotation of objects on the image. From this we may calculate the offset and perform an image rotation to correct eventual miss alignments. diff --git a/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.markdown b/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.markdown index 941f005ae0..c0d48a178d 100644 --- a/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.markdown +++ b/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.markdown @@ -16,18 +16,13 @@ Source code ----------- You can [download this from here -](samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp) or find it in the +](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp) or find it in the `samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp` of the OpenCV source code library. Here's a sample code of how to achieve all the stuff enumerated at the goal list. -@dontinclude cpp/tutorial_code/core/file_input_output/file_input_output.cpp - -@until std; -@skip class MyData -@until return 0; -@until } +@includelineno cpp/tutorial_code/core/file_input_output/file_input_output.cpp Explanation ----------- diff --git a/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.rst b/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.rst deleted file mode 100644 index 7e1674efaf..0000000000 --- a/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.rst +++ /dev/null @@ -1,279 +0,0 @@ -.. _fileInputOutputXMLYAML: - -File Input and Output using XML and YAML files -********************************************** - -Goal -==== - -You'll find answers for the following questions: - -.. container:: enumeratevisibleitemswithsquare - - + How to print and read text entries to a file and OpenCV using YAML or XML files? - + How to do the same for OpenCV data structures? - + How to do this for your data structures? - + Usage of OpenCV data structures such as :xmlymlpers:`FileStorage `, :xmlymlpers:`FileNode ` or :xmlymlpers:`FileNodeIterator `. - -Source code -=========== - -You can :download:`download this from here <../../../../samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp>` or find it in the :file:`samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp` of the OpenCV source code library. - -Here's a sample code of how to achieve all the stuff enumerated at the goal list. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 1-7, 21-154 - -Explanation -=========== - -Here we talk only about XML and YAML file inputs. Your output (and its respective input) file may have only one of these extensions and the structure coming from this. They are two kinds of data structures you may serialize: *mappings* (like the STL map) and *element sequence* (like the STL vector). The difference between these is that in a map every element has a unique name through what you may access it. For sequences you need to go through them to query a specific item. - -1. **XML/YAML File Open and Close.** Before you write any content to such file you need to open it and at the end to close it. The XML/YAML data structure in OpenCV is :xmlymlpers:`FileStorage `. To specify that this structure to which file binds on your hard drive you can use either its constructor or the *open()* function of this: - - .. code-block:: cpp - - string filename = "I.xml"; - FileStorage fs(filename, FileStorage::WRITE); - //... - fs.open(filename, FileStorage::READ); - - Either one of this you use the second argument is a constant specifying the type of operations you'll be able to on them: WRITE, READ or APPEND. The extension specified in the file name also determinates the output format that will be used. The output may be even compressed if you specify an extension such as *.xml.gz*. - - The file automatically closes when the :xmlymlpers:`FileStorage ` objects is destroyed. However, you may explicitly call for this by using the *release* function: - - .. code-block:: cpp - - fs.release(); // explicit close - -#. **Input and Output of text and numbers.** The data structure uses the same << output operator that the STL library. For outputting any type of data structure we need first to specify its name. We do this by just simply printing out the name of this. For basic types you may follow this with the print of the value : - - .. code-block:: cpp - - fs << "iterationNr" << 100; - - Reading in is a simple addressing (via the [] operator) and casting operation or a read via the >> operator : - - .. code-block:: cpp - - int itNr; - fs["iterationNr"] >> itNr; - itNr = (int) fs["iterationNr"]; - -#. **Input/Output of OpenCV Data structures.** Well these behave exactly just as the basic C++ types: - - .. code-block:: cpp - - Mat R = Mat_::eye (3, 3), - T = Mat_::zeros(3, 1); - - fs << "R" << R; // Write cv::Mat - fs << "T" << T; - - fs["R"] >> R; // Read cv::Mat - fs["T"] >> T; - -#. **Input/Output of vectors (arrays) and associative maps.** As I mentioned beforehand, we can output maps and sequences (array, vector) too. Again we first print the name of the variable and then we have to specify if our output is either a sequence or map. - - For sequence before the first element print the "[" character and after the last one the "]" character: - - .. code-block:: cpp - - fs << "strings" << "["; // text - string sequence - fs << "image1.jpg" << "Awesomeness" << "baboon.jpg"; - fs << "]"; // close sequence - - For maps the drill is the same however now we use the "{" and "}" delimiter characters: - - .. code-block:: cpp - - fs << "Mapping"; // text - mapping - fs << "{" << "One" << 1; - fs << "Two" << 2 << "}"; - - To read from these we use the :xmlymlpers:`FileNode ` and the :xmlymlpers:`FileNodeIterator ` data structures. The [] operator of the :xmlymlpers:`FileStorage ` class returns a :xmlymlpers:`FileNode ` data type. If the node is sequential we can use the :xmlymlpers:`FileNodeIterator ` to iterate through the items: - - .. code-block:: cpp - - FileNode n = fs["strings"]; // Read string sequence - Get node - if (n.type() != FileNode::SEQ) - { - cerr << "strings is not a sequence! FAIL" << endl; - return 1; - } - - FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node - for (; it != it_end; ++it) - cout << (string)*it << endl; - - For maps you can use the [] operator again to acces the given item (or the >> operator too): - - .. code-block:: cpp - - n = fs["Mapping"]; // Read mappings from a sequence - cout << "Two " << (int)(n["Two"]) << "; "; - cout << "One " << (int)(n["One"]) << endl << endl; - -#. **Read and write your own data structures.** Suppose you have a data structure such as: - - .. code-block:: cpp - - class MyData - { - public: - MyData() : A(0), X(0), id() {} - public: // Data Members - int A; - double X; - string id; - }; - - It's possible to serialize this through the OpenCV I/O XML/YAML interface (just as in case of the OpenCV data structures) by adding a read and a write function inside and outside of your class. For the inside part: - - .. code-block:: cpp - - void write(FileStorage& fs) const //Write serialization for this class - { - fs << "{" << "A" << A << "X" << X << "id" << id << "}"; - } - - void read(const FileNode& node) //Read serialization for this class - { - A = (int)node["A"]; - X = (double)node["X"]; - id = (string)node["id"]; - } - - Then you need to add the following functions definitions outside the class: - - .. code-block:: cpp - - void write(FileStorage& fs, const std::string&, const MyData& x) - { - x.write(fs); - } - - void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()) - { - if(node.empty()) - x = default_value; - else - x.read(node); - } - - Here you can observe that in the read section we defined what happens if the user tries to read a non-existing node. In this case we just return the default initialization value, however a more verbose solution would be to return for instance a minus one value for an object ID. - - Once you added these four functions use the >> operator for write and the << operator for read: - - .. code-block:: cpp - - MyData m(1); - fs << "MyData" << m; // your own data structures - fs["MyData"] >> m; // Read your own structure_ - - Or to try out reading a non-existing read: - - .. code-block:: cpp - - fs["NonExisting"] >> m; // Do not add a fs << "NonExisting" << m command for this to work - cout << endl << "NonExisting = " << endl << m << endl; - -Result -====== - -Well mostly we just print out the defined numbers. On the screen of your console you could see: - -.. code-block:: bash - - Write Done. - - Reading: - 100image1.jpg - Awesomeness - baboon.jpg - Two 2; One 1 - - - R = [1, 0, 0; - 0, 1, 0; - 0, 0, 1] - T = [0; 0; 0] - - MyData = - { id = mydata1234, X = 3.14159, A = 97} - - Attempt to read NonExisting (should initialize the data structure with its default). - NonExisting = - { id = , X = 0, A = 0} - - Tip: Open up output.xml with a text editor to see the serialized data. - -Nevertheless, it's much more interesting what you may see in the output xml file: - -.. code-block:: xml - - - - 100 - - image1.jpg Awesomeness baboon.jpg - - 1 - 2 - - 3 - 3 -
u
- - 1 0 0 0 1 0 0 0 1
- - 3 - 1 -
d
- - 0. 0. 0.
- - 97 - 3.1415926535897931e+000 - mydata1234 -
- -Or the YAML file: - -.. code-block:: yaml - - %YAML:1.0 - iterationNr: 100 - strings: - - "image1.jpg" - - Awesomeness - - "baboon.jpg" - Mapping: - One: 1 - Two: 2 - R: !!opencv-matrix - rows: 3 - cols: 3 - dt: u - data: [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ] - T: !!opencv-matrix - rows: 3 - cols: 1 - dt: d - data: [ 0., 0., 0. ] - MyData: - A: 97 - X: 3.1415926535897931e+000 - id: mydata1234 - -You may observe a runtime instance of this on the `YouTube here `_ . - -.. raw:: html - -
- -
diff --git a/doc/tutorials/core/how_to_scan_images/how_to_scan_images.markdown b/doc/tutorials/core/how_to_scan_images/how_to_scan_images.markdown index e96b145a26..6cae0cfae8 100644 --- a/doc/tutorials/core/how_to_scan_images/how_to_scan_images.markdown +++ b/doc/tutorials/core/how_to_scan_images/how_to_scan_images.markdown @@ -51,7 +51,7 @@ three major ways of going through an image pixel by pixel. To make things a litt will make the scanning for each image using all of these methods, and print out how long it took. You can download the full source code [here -](samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp) or look it up in +](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp) or look it up in the samples directory of OpenCV at the cpp tutorial code for the core section. Its basic usage is: @code{.bash} how_to_scan_images imageName.jpg intValueToReduce [G] @@ -59,10 +59,7 @@ how_to_scan_images imageName.jpg intValueToReduce [G] The final argument is optional. If given the image will be loaded in gray scale format, otherwise the RGB color way is used. The first thing is to calculate the lookup table. -@dontinclude cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp - -@skip int divideWith -@until table[i] +@snippet how_to_scan_images.cpp dividewith Here we first use the C++ *stringstream* class to convert the third command line argument from text to an integer format. Then we use a simple look and the upper formula to calculate the lookup table. @@ -107,9 +104,7 @@ The efficient way When it comes to performance you cannot beat the classic C style operator[] (pointer) access. Therefore, the most efficient method we can recommend for making the assignment is: -@skip Mat& ScanImageAndReduceC -@until return -@until } +@snippet how_to_scan_images.cpp scan-c Here we basically just acquire a pointer to the start of each row and go through it until it ends. In the special case that the matrix is stored in a continues manner we only need to request the @@ -141,9 +136,7 @@ considered a safer way as it takes over these tasks from the user. All you need begin and the end of the image matrix and then just increase the begin iterator until you reach the end. To acquire the value *pointed* by the iterator use the \* operator (add it before it). -@skip ScanImageAndReduceIterator -@until return -@until } +@snippet how_to_scan_images.cpp scan-iterator In case of color images we have three uchar items per column. This may be considered a short vector of uchar items, that has been baptized in OpenCV with the *Vec3b* name. To access the n-th sub @@ -161,9 +154,7 @@ what type we are looking at the image. It's no different here as you need manual type to use at the automatic lookup. You can observe this in case of the gray scale images for the following source code (the usage of the + @ref cv::at() function): -@skip ScanImageAndReduceRandomAccess -@until return -@until } +@snippet how_to_scan_images.cpp scan-random The functions takes your input type and coordinates and calculates on the fly the address of the queried item. Then returns a reference to that. This may be a constant when you *get* the value and @@ -192,14 +183,11 @@ OpenCV has a function that makes the modification without the need from you to w the image. We use the @ref cv::LUT() function of the core module. First we build a Mat type of the lookup table: -@dontinclude cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp - -@skip Mat lookUpTable -@until p[i] = table[i] +@snippet how_to_scan_images.cpp table-init Finally call the function (I is our input image and J the output one): -@skipline LUT +@snippet how_to_scan_images.cpp table-use Performance Difference ---------------------- diff --git a/doc/tutorials/core/how_to_scan_images/how_to_scan_images.rst b/doc/tutorials/core/how_to_scan_images/how_to_scan_images.rst deleted file mode 100644 index 6162985ddb..0000000000 --- a/doc/tutorials/core/how_to_scan_images/how_to_scan_images.rst +++ /dev/null @@ -1,183 +0,0 @@ -.. _howToScanImagesOpenCV: - -How to scan images, lookup tables and time measurement with OpenCV -******************************************************************* - -Goal -==== - -We'll seek answers for the following questions: - -.. container:: enumeratevisibleitemswithsquare - - + How to go through each and every pixel of an image? - + How is OpenCV matrix values stored? - + How to measure the performance of our algorithm? - + What are lookup tables and why use them? - -Our test case -============= - -Let us consider a simple color reduction method. By using the unsigned char C and C++ type for matrix item storing, a channel of pixel may have up to 256 different values. For a three channel image this can allow the formation of way too many colors (16 million to be exact). Working with so many color shades may give a heavy blow to our algorithm performance. However, sometimes it is enough to work with a lot less of them to get the same final result. - -In this cases it's common that we make a *color space reduction*. This means that we divide the color space current value with a new input value to end up with fewer colors. For instance every value between zero and nine takes the new value zero, every value between ten and nineteen the value ten and so on. - -When you divide an *uchar* (unsigned char - aka values between zero and 255) value with an *int* value the result will be also *char*. These values may only be char values. Therefore, any fraction will be rounded down. Taking advantage of this fact the upper operation in the *uchar* domain may be expressed as: - -.. math:: - - I_{new} = (\frac{I_{old}}{10}) * 10 - -A simple color space reduction algorithm would consist of just passing through every pixel of an image matrix and applying this formula. It's worth noting that we do a divide and a multiplication operation. These operations are bloody expensive for a system. If possible it's worth avoiding them by using cheaper operations such as a few subtractions, addition or in best case a simple assignment. Furthermore, note that we only have a limited number of input values for the upper operation. In case of the *uchar* system this is 256 to be exact. - -Therefore, for larger images it would be wise to calculate all possible values beforehand and during the assignment just make the assignment, by using a lookup table. Lookup tables are simple arrays (having one or more dimensions) that for a given input value variation holds the final output value. Its strength lies that we do not need to make the calculation, we just need to read the result. - -Our test case program (and the sample presented here) will do the following: read in a console line argument image (that may be either color or gray scale - console line argument too) and apply the reduction with the given console line argument integer value. In OpenCV, at the moment they are three major ways of going through an image pixel by pixel. To make things a little more interesting will make the scanning for each image using all of these methods, and print out how long it took. - -You can download the full source code :download:`here <../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp>` or look it up in the samples directory of OpenCV at the cpp tutorial code for the core section. Its basic usage is: - -.. code-block:: bash - - how_to_scan_images imageName.jpg intValueToReduce [G] - -The final argument is optional. If given the image will be loaded in gray scale format, otherwise the RGB color way is used. The first thing is to calculate the lookup table. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp - :language: cpp - :tab-width: 4 - :lines: 49-61 - -Here we first use the C++ *stringstream* class to convert the third command line argument from text to an integer format. Then we use a simple look and the upper formula to calculate the lookup table. No OpenCV specific stuff here. - -Another issue is how do we measure time? Well OpenCV offers two simple functions to achieve this :UtilitySystemFunctions:`getTickCount() ` and :UtilitySystemFunctions:`getTickFrequency() `. The first returns the number of ticks of your systems CPU from a certain event (like since you booted your system). The second returns how many times your CPU emits a tick during a second. So to measure in seconds the number of time elapsed between two operations is easy as: - -.. code-block:: cpp - - double t = (double)getTickCount(); - // do something ... - t = ((double)getTickCount() - t)/getTickFrequency(); - cout << "Times passed in seconds: " << t << endl; - -.. _How_Image_Stored_Memory: - -How the image matrix is stored in the memory? -============================================= - -As you could already read in my :ref:`matTheBasicImageContainer` tutorial the size of the matrix depends of the color system used. More accurately, it depends from the number of channels used. In case of a gray scale image we have something like: - -.. math:: - - \newcommand{\tabItG}[1] { \textcolor{black}{#1} \cellcolor[gray]{0.8}} - \begin{tabular} {ccccc} - ~ & \multicolumn{1}{c}{Column 0} & \multicolumn{1}{c}{Column 1} & \multicolumn{1}{c}{Column ...} & \multicolumn{1}{c}{Column m}\\ - Row 0 & \tabItG{0,0} & \tabItG{0,1} & \tabItG{...} & \tabItG{0, m} \\ - Row 1 & \tabItG{1,0} & \tabItG{1,1} & \tabItG{...} & \tabItG{1, m} \\ - Row ... & \tabItG{...,0} & \tabItG{...,1} & \tabItG{...} & \tabItG{..., m} \\ - Row n & \tabItG{n,0} & \tabItG{n,1} & \tabItG{n,...} & \tabItG{n, m} \\ - \end{tabular} - -For multichannel images the columns contain as many sub columns as the number of channels. For example in case of an RGB color system: - -.. math:: - - \newcommand{\tabIt}[1] { \textcolor{yellow}{#1} \cellcolor{blue} & \textcolor{black}{#1} \cellcolor{green} & \textcolor{black}{#1} \cellcolor{red}} - \begin{tabular} {ccccccccccccc} - ~ & \multicolumn{3}{c}{Column 0} & \multicolumn{3}{c}{Column 1} & \multicolumn{3}{c}{Column ...} & \multicolumn{3}{c}{Column m}\\ - Row 0 & \tabIt{0,0} & \tabIt{0,1} & \tabIt{...} & \tabIt{0, m} \\ - Row 1 & \tabIt{1,0} & \tabIt{1,1} & \tabIt{...} & \tabIt{1, m} \\ - Row ... & \tabIt{...,0} & \tabIt{...,1} & \tabIt{...} & \tabIt{..., m} \\ - Row n & \tabIt{n,0} & \tabIt{n,1} & \tabIt{n,...} & \tabIt{n, m} \\ - \end{tabular} - -Note that the order of the channels is inverse: BGR instead of RGB. Because in many cases the memory is large enough to store the rows in a successive fashion the rows may follow one after another, creating a single long row. Because everything is in a single place following one after another this may help to speed up the scanning process. We can use the :basicstructures:`isContinuous() ` function to *ask* the matrix if this is the case. Continue on to the next section to find an example. - -The efficient way -================= - -When it comes to performance you cannot beat the classic C style operator[] (pointer) access. Therefore, the most efficient method we can recommend for making the assignment is: - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp - :language: cpp - :tab-width: 4 - :lines: 126-153 - -Here we basically just acquire a pointer to the start of each row and go through it until it ends. In the special case that the matrix is stored in a continues manner we only need to request the pointer a single time and go all the way to the end. We need to look out for color images: we have three channels so we need to pass through three times more items in each row. - -There's another way of this. The *data* data member of a *Mat* object returns the pointer to the first row, first column. If this pointer is null you have no valid input in that object. Checking this is the simplest method to check if your image loading was a success. In case the storage is continues we can use this to go through the whole data pointer. In case of a gray scale image this would look like: - -.. code-block:: cpp - - uchar* p = I.data; - - for( unsigned int i =0; i < ncol*nrows; ++i) - *p++ = table[*p]; - -You would get the same result. However, this code is a lot harder to read later on. It gets even harder if you have some more advanced technique there. Moreover, in practice I've observed you'll get the same performance result (as most of the modern compilers will probably make this small optimization trick automatically for you). - -The iterator (safe) method -========================== - -In case of the efficient way making sure that you pass through the right amount of *uchar* fields and to skip the gaps that may occur between the rows was your responsibility. The iterator method is considered a safer way as it takes over these tasks from the user. All you need to do is ask the begin and the end of the image matrix and then just increase the begin iterator until you reach the end. To acquire the value *pointed* by the iterator use the * operator (add it before it). - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp - :language: cpp - :tab-width: 4 - :lines: 155-183 - -In case of color images we have three uchar items per column. This may be considered a short vector of uchar items, that has been baptized in OpenCV with the *Vec3b* name. To access the n-th sub column we use simple operator[] access. It's important to remember that OpenCV iterators go through the columns and automatically skip to the next row. Therefore in case of color images if you use a simple *uchar* iterator you'll be able to access only the blue channel values. - -On-the-fly address calculation with reference returning -======================================================= - -The final method isn't recommended for scanning. It was made to acquire or modify somehow random elements in the image. Its basic usage is to specify the row and column number of the item you want to access. During our earlier scanning methods you could already observe that is important through what type we are looking at the image. It's no different here as you need manually to specify what type to use at the automatic lookup. You can observe this in case of the gray scale images for the following source code (the usage of the + :basicstructures:`at() ` function): - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp - :language: cpp - :tab-width: 4 - :lines: 185-217 - -The functions takes your input type and coordinates and calculates on the fly the address of the queried item. Then returns a reference to that. This may be a constant when you *get* the value and non-constant when you *set* the value. As a safety step in **debug mode only*** there is performed a check that your input coordinates are valid and does exist. If this isn't the case you'll get a nice output message of this on the standard error output stream. Compared to the efficient way in release mode the only difference in using this is that for every element of the image you'll get a new row pointer for what we use the C operator[] to acquire the column element. - -If you need to multiple lookups using this method for an image it may be troublesome and time consuming to enter the type and the at keyword for each of the accesses. To solve this problem OpenCV has a :basicstructures:`Mat_ ` data type. It's the same as Mat with the extra need that at definition you need to specify the data type through what to look at the data matrix, however in return you can use the operator() for fast access of items. To make things even better this is easily convertible from and to the usual :basicstructures:`Mat ` data type. A sample usage of this you can see in case of the color images of the upper function. Nevertheless, it's important to note that the same operation (with the same runtime speed) could have been done with the :basicstructures:`at() ` function. It's just a less to write for the lazy programmer trick. - -The Core Function -================= - -This is a bonus method of achieving lookup table modification in an image. Because in image processing it's quite common that you want to replace all of a given image value to some other value OpenCV has a function that makes the modification without the need from you to write the scanning of the image. We use the :operationsOnArrays:`LUT() ` function of the core module. First we build a Mat type of the lookup table: - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp - :language: cpp - :tab-width: 4 - :lines: 108-111 - -Finally call the function (I is our input image and J the output one): - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp - :language: cpp - :tab-width: 4 - :lines: 116 - -Performance Difference -====================== - -For the best result compile the program and run it on your own speed. For showing off better the differences I've used a quite large (2560 X 1600) image. The performance presented here are for color images. For a more accurate value I've averaged the value I got from the call of the function for hundred times. - -============= ==================== -Efficient Way 79.4717 milliseconds - -Iterator 83.7201 milliseconds - -On-The-Fly RA 93.7878 milliseconds - -LUT function 32.5759 milliseconds -============= ==================== - -We can conclude a couple of things. If possible, use the already made functions of OpenCV (instead reinventing these). The fastest method turns out to be the LUT function. This is because the OpenCV library is multi-thread enabled via Intel Threaded Building Blocks. However, if you need to write a simple image scan prefer the pointer method. The iterator is a safer bet, however quite slower. Using the on-the-fly reference access method for full image scan is the most costly in debug mode. In the release mode it may beat the iterator approach or not, however it surely sacrifices for this the safety trait of iterators. - -Finally, you may watch a sample run of the program on the `video posted `_ on our YouTube channel. - -.. raw:: html - -
- -
diff --git a/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown b/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown index c52a1e9d7d..9ab241a63b 100644 --- a/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown +++ b/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown @@ -16,7 +16,7 @@ Code You may also find the source code in the `samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp` file of the OpenCV source library or -download it from [here](samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp). +download it from [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp). @includelineno cpp/tutorial_code/core/ippasync/ippasync_sample.cpp diff --git a/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.rst b/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.rst deleted file mode 100644 index 43f1f22d30..0000000000 --- a/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.rst +++ /dev/null @@ -1,164 +0,0 @@ -.. _howToUseIPPAconversion: - -Intel® IPP Asynchronous C/C++ library in OpenCV -*********************************************** - -Goal -==== - -.. _hppiSobel: http://software.intel.com/en-us/node/474701 -.. _hppiMatrix: http://software.intel.com/en-us/node/501660 - -The tutorial demonstrates the `Intel® IPP Asynchronous C/C++ `_ library usage with OpenCV. -The code example below illustrates implementation of the Sobel operation, accelerated with Intel® IPP Asynchronous C/C++ functions. -In this code example, :ippa_convert:`hpp::getMat <>` and :ippa_convert:`hpp::getHpp <>` functions are used for data conversion between hppiMatrix_ and ``Mat`` matrices. - -Code -==== - -You may also find the source code in the :file:`samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp` -file of the OpenCV source library or :download:`download it from here -<../../../../samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp>`. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp - :language: cpp - :linenos: - :tab-width: 4 - -Explanation -=========== - -#. Create parameters for OpenCV: - - .. code-block:: cpp - - VideoCapture cap; - Mat image, gray, result; - - and IPP Async: - - .. code-block:: cpp - - hppiMatrix* src,* dst; - hppAccel accel = 0; - hppAccelType accelType; - hppStatus sts; - hppiVirtualMatrix * virtMatrix; - -#. Load input image or video. How to open and read video stream you can see in the :ref:`videoInputPSNRMSSIM` tutorial. - - .. code-block:: cpp - - if( useCamera ) - { - printf("used camera\n"); - cap.open(0); - } - else - { - printf("used image %s\n", file.c_str()); - cap.open(file.c_str()); - } - - if( !cap.isOpened() ) - { - printf("can not open camera or video file\n"); - return -1; - } - -#. Create accelerator instance using `hppCreateInstance `_: - - .. code-block:: cpp - - accelType = sAccel == "cpu" ? HPP_ACCEL_TYPE_CPU: - sAccel == "gpu" ? HPP_ACCEL_TYPE_GPU: - HPP_ACCEL_TYPE_ANY; - - //Create accelerator instance - sts = hppCreateInstance(accelType, 0, &accel); - CHECK_STATUS(sts, "hppCreateInstance"); - -#. Create an array of virtual matrices using `hppiCreateVirtualMatrices `_ function. - - .. code-block:: cpp - - virtMatrix = hppiCreateVirtualMatrices(accel, 1); - -#. Prepare a matrix for input and output data: - - .. code-block:: cpp - - cap >> image; - if(image.empty()) - break; - - cvtColor( image, gray, COLOR_BGR2GRAY ); - - result.create( image.rows, image.cols, CV_8U); - -#. Convert ``Mat`` to hppiMatrix_ using :ippa_convert:`getHpp <>` and call hppiSobel_ function. - - .. code-block:: cpp - - //convert Mat to hppiMatrix - src = getHpp(gray, accel); - dst = getHpp(result, accel); - - sts = hppiSobel(accel,src, HPP_MASK_SIZE_3X3,HPP_NORM_L1,virtMatrix[0]); - CHECK_STATUS(sts,"hppiSobel"); - - sts = hppiConvert(accel, virtMatrix[0], 0, HPP_RND_MODE_NEAR, dst, HPP_DATA_TYPE_8U); - CHECK_STATUS(sts,"hppiConvert"); - - // Wait for tasks to complete - sts = hppWait(accel, HPP_TIME_OUT_INFINITE); - CHECK_STATUS(sts, "hppWait"); - - We use `hppiConvert `_ because hppiSobel_ returns destination - matrix with ``HPP_DATA_TYPE_16S`` data type for source matrix with ``HPP_DATA_TYPE_8U`` type. - You should check ``hppStatus`` after each call IPP Async function. - -#. Create windows and show the images, the usual way. - - .. code-block:: cpp - - imshow("image", image); - imshow("rez", result); - - waitKey(15); - -#. Delete hpp matrices. - - .. code-block:: cpp - - sts = hppiFreeMatrix(src); - CHECK_DEL_STATUS(sts,"hppiFreeMatrix"); - - sts = hppiFreeMatrix(dst); - CHECK_DEL_STATUS(sts,"hppiFreeMatrix"); - -#. Delete virtual matrices and accelerator instance. - - .. code-block:: cpp - - if (virtMatrix) - { - sts = hppiDeleteVirtualMatrices(accel, virtMatrix); - CHECK_DEL_STATUS(sts,"hppiDeleteVirtualMatrices"); - } - - if (accel) - { - sts = hppDeleteInstance(accel); - CHECK_DEL_STATUS(sts, "hppDeleteInstance"); - } - -Result -======= - -After compiling the code above we can execute it giving an image or video path and accelerator type as an argument. -For this tutorial we use baboon.png image as input. The result is below. - - .. image:: images/How_To_Use_IPPA_Result.jpg - :alt: Final Result - :align: center \ No newline at end of file diff --git a/doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.jpg b/doc/tutorials/core/images/Adding_Images_Tutorial_Result_0.jpg similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/Adding_Images_Tutorial_Result_0.jpg rename to doc/tutorials/core/images/Adding_Images_Tutorial_Result_0.jpg diff --git a/doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.jpg b/doc/tutorials/core/images/Basic_Linear_Transform_Tutorial_Result_0.jpg similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/Basic_Linear_Transform_Tutorial_Result_0.jpg rename to doc/tutorials/core/images/Basic_Linear_Transform_Tutorial_Result_0.jpg diff --git a/doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.jpg b/doc/tutorials/core/images/Drawing_1_Tutorial_Result_0.jpg similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/Drawing_1_Tutorial_Result_0.jpg rename to doc/tutorials/core/images/Drawing_1_Tutorial_Result_0.jpg diff --git a/doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.jpg b/doc/tutorials/core/images/Drawing_2_Tutorial_Result_7.jpg similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/Drawing_2_Tutorial_Result_7.jpg rename to doc/tutorials/core/images/Drawing_2_Tutorial_Result_7.jpg diff --git a/doc/tutorials/core/table_of_content_core/images/How_To_Use_IPPA.jpg b/doc/tutorials/core/images/How_To_Use_IPPA.jpg similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/How_To_Use_IPPA.jpg rename to doc/tutorials/core/images/How_To_Use_IPPA.jpg diff --git a/doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.jpg b/doc/tutorials/core/images/Morphology_1_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/Morphology_1_Tutorial_Cover.jpg rename to doc/tutorials/core/images/Morphology_1_Tutorial_Cover.jpg diff --git a/doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.jpg b/doc/tutorials/core/images/Smoothing_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/Smoothing_Tutorial_Cover.jpg rename to doc/tutorials/core/images/Smoothing_Tutorial_Cover.jpg diff --git a/doc/tutorials/core/table_of_content_core/images/discrete_fourier_transform.png b/doc/tutorials/core/images/discrete_fourier_transform.png similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/discrete_fourier_transform.png rename to doc/tutorials/core/images/discrete_fourier_transform.png diff --git a/doc/tutorials/core/table_of_content_core/images/file_input_output_with_xml_yml.png b/doc/tutorials/core/images/file_input_output_with_xml_yml.png similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/file_input_output_with_xml_yml.png rename to doc/tutorials/core/images/file_input_output_with_xml_yml.png diff --git a/doc/tutorials/core/table_of_content_core/images/howToScanImages.jpg b/doc/tutorials/core/images/howToScanImages.jpg similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/howToScanImages.jpg rename to doc/tutorials/core/images/howToScanImages.jpg diff --git a/doc/tutorials/core/table_of_content_core/images/interopOpenCV1.png b/doc/tutorials/core/images/interopOpenCV1.png similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/interopOpenCV1.png rename to doc/tutorials/core/images/interopOpenCV1.png diff --git a/doc/tutorials/core/table_of_content_core/images/matMaskFilter2DOp.png b/doc/tutorials/core/images/matMaskFilter2DOp.png similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/matMaskFilter2DOp.png rename to doc/tutorials/core/images/matMaskFilter2DOp.png diff --git a/doc/tutorials/core/table_of_content_core/images/matTheBasicImageStructure.jpg b/doc/tutorials/core/images/matTheBasicImageStructure.jpg similarity index 100% rename from doc/tutorials/core/table_of_content_core/images/matTheBasicImageStructure.jpg rename to doc/tutorials/core/images/matTheBasicImageStructure.jpg diff --git a/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown b/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown index 589e31f6fc..5f27228508 100644 --- a/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown +++ b/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown @@ -85,7 +85,7 @@ L = Mat(pI); A case study ------------ -Now that you have the basics done [here's](samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp) +Now that you have the basics done [here's](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp) an example that mixes the usage of the C interface with the C++ one. You will also find it in the sample directory of the OpenCV source code library at the `samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp` . @@ -93,18 +93,13 @@ To further help on seeing the difference the programs supports two modes: one mi one pure C++. If you define the *DEMO_MIXED_API_USE* you'll end up using the first. The program separates the color planes, does some modifications on them and in the end merge them back together. -@dontinclude cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp -@until namespace cv -@skip ifdef -@until endif -@skip main -@until endif +@snippet interoperability_with_OpenCV_1.cpp head +@snippet interoperability_with_OpenCV_1.cpp start Here you can observe that with the new structure we have no pointer problems, although it is possible to use the old functions and in the end just transform the result to a *Mat* object. -@skip convert image -@until split +@snippet interoperability_with_OpenCV_1.cpp new Because, we want to mess around with the images luma component we first convert from the default RGB to the YUV color space and then split the result up into separate planes. Here the program splits: @@ -114,8 +109,7 @@ image some Gaussian noise and then mix together the channels according to some f The scanning version looks like: -@skip #if 1 -@until #else +@snippet interoperability_with_OpenCV_1.cpp scanning Here you can observe that we may go through all the pixels of an image in three fashions: an iterator, a C pointer and an individual element access style. You can read a more in-depth @@ -123,14 +117,12 @@ description of these in the @ref tutorial_how_to_scan_images tutorial. Convertin names is easy. Just remove the cv prefix and use the new *Mat* data structure. Here's an example of this by using the weighted addition function: -@until planes[0] -@until endif +@snippet interoperability_with_OpenCV_1.cpp noisy As you may observe the *planes* variable is of type *Mat*. However, converting from *Mat* to *IplImage* is easy and made automatically with a simple assignment operator. -@skip merge(planes -@until #endif +@snippet interoperability_with_OpenCV_1.cpp end The new *imshow* highgui function accepts both the *Mat* and *IplImage* data structures. Compile and run the program and if the first image below is your input you may get either the first or second as @@ -140,7 +132,7 @@ output: You may observe a runtime instance of this on the [YouTube here](https://www.youtube.com/watch?v=qckm-zvo31w) and you can [download the source code from here -](samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp) +](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp) or find it in the `samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp` of the OpenCV source code library. diff --git a/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.rst b/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.rst deleted file mode 100644 index 9d4189363f..0000000000 --- a/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.rst +++ /dev/null @@ -1,129 +0,0 @@ -.. _InteroperabilityWithOpenCV1: - -Interoperability with OpenCV 1 -****************************** - -Goal -==== - -For the OpenCV developer team it's important to constantly improve the library. We are constantly thinking about methods that will ease your work process, while still maintain the libraries flexibility. The new C++ interface is a development of us that serves this goal. Nevertheless, backward compatibility remains important. We do not want to break your code written for earlier version of the OpenCV library. Therefore, we made sure that we add some functions that deal with this. In the following you'll learn: - -.. container:: enumeratevisibleitemswithsquare - - + What changed with the version 2 of OpenCV in the way you use the library compared to its first version - + How to add some Gaussian noise to an image - + What are lookup tables and why use them? - -General -======= - -When making the switch you first need to learn some about the new data structure for images: :ref:`matTheBasicImageContainer`, this replaces the old *CvMat* and *IplImage* ones. Switching to the new functions is easier. You just need to remember a couple of new things. - -OpenCV 2 received reorganization. No longer are all the functions crammed into a single library. We have many modules, each of them containing data structures and functions relevant to certain tasks. This way you do not need to ship a large library if you use just a subset of OpenCV. This means that you should also include only those headers you will use. For example: - -.. code-block:: cpp - - #include - #include - #include - - -All the OpenCV related stuff is put into the *cv* namespace to avoid name conflicts with other libraries data structures and functions. Therefore, either you need to prepend the *cv::* keyword before everything that comes from OpenCV or after the includes, you just add a directive to use this: - -.. code-block:: cpp - - using namespace cv; // The new C++ interface API is inside this namespace. Import it. - -Because the functions are already in a namespace there is no need for them to contain the *cv* prefix in their name. As such all the new C++ compatible functions don't have this and they follow the camel case naming rule. This means the first letter is small (unless it's a name, like Canny) and the subsequent words start with a capital letter (like *copyMakeBorder*). - -Now, remember that you need to link to your application all the modules you use, and in case you are on Windows using the *DLL* system you will need to add, again, to the path all the binaries. For more in-depth information if you're on Windows read :ref:`Windows_Visual_Studio_How_To` and for Linux an example usage is explained in :ref:`Linux_Eclipse_Usage`. - -Now for converting the *Mat* object you can use either the *IplImage* or the *CvMat* operators. While in the C interface you used to work with pointers here it's no longer the case. In the C++ interface we have mostly *Mat* objects. These objects may be freely converted to both *IplImage* and *CvMat* with simple assignment. For example: - -.. code-block:: cpp - - Mat I; - IplImage pI = I; - CvMat mI = I; - -Now if you want pointers the conversion gets just a little more complicated. The compilers can no longer automatically determinate what you want and as you need to explicitly specify your goal. This is to call the *IplImage* and *CvMat* operators and then get their pointers. For getting the pointer we use the & sign: - -.. code-block:: cpp - - Mat I; - IplImage* pI = &I.operator IplImage(); - CvMat* mI = &I.operator CvMat(); - -One of the biggest complaints of the C interface is that it leaves all the memory management to you. You need to figure out when it is safe to release your unused objects and make sure you do so before the program finishes or you could have troublesome memory leeks. To work around this issue in OpenCV there is introduced a sort of smart pointer. This will automatically release the object when it's no longer in use. To use this declare the pointers as a specialization of the *Ptr* : - -.. code-block:: cpp - - Ptr piI = &I.operator IplImage(); - -Converting from the C data structures to the *Mat* is done by passing these inside its constructor. For example: - -.. code-block:: cpp - - Mat K(piL), L; - L = Mat(pI); - -A case study -============ - -Now that you have the basics done :download:`here's <../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp>` an example that mixes the usage of the C interface with the C++ one. You will also find it in the sample directory of the OpenCV source code library at the :file:`samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp` . To further help on seeing the difference the programs supports two modes: one mixed C and C++ and one pure C++. If you define the *DEMO_MIXED_API_USE* you'll end up using the first. The program separates the color planes, does some modifications on them and in the end merge them back together. - - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 1-10, 23-26, 29-46 - -Here you can observe that with the new structure we have no pointer problems, although it is possible to use the old functions and in the end just transform the result to a *Mat* object. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 48-53 - -Because, we want to mess around with the images luma component we first convert from the default RGB to the YUV color space and then split the result up into separate planes. Here the program splits: in the first example it processes each plane using one of the three major image scanning algorithms in OpenCV (C [] operator, iterator, individual element access). In a second variant we add to the image some Gaussian noise and then mix together the channels according to some formula. - -The scanning version looks like: - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 57-77 - -Here you can observe that we may go through all the pixels of an image in three fashions: an iterator, a C pointer and an individual element access style. You can read a more in-depth description of these in the :ref:`howToScanImagesOpenCV` tutorial. Converting from the old function names is easy. Just remove the cv prefix and use the new *Mat* data structure. Here's an example of this by using the weighted addition function: - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 81-113 - -As you may observe the *planes* variable is of type *Mat*. However, converting from *Mat* to *IplImage* is easy and made automatically with a simple assignment operator. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 117-129 - -The new *imshow* highgui function accepts both the *Mat* and *IplImage* data structures. Compile and run the program and if the first image below is your input you may get either the first or second as output: - -.. image:: images/outputInteropOpenCV1.jpg - :alt: The output of the sample - :align: center - - -You may observe a runtime instance of this on the `YouTube here `_ and you can :download:`download the source code from here <../../../../samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp>` or find it in the :file:`samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp` of the OpenCV source code library. - -.. raw:: html - -
- -
diff --git a/doc/tutorials/core/mat-mask-operations/mat-mask-operations.rst b/doc/tutorials/core/mat-mask-operations/mat-mask-operations.rst deleted file mode 100644 index dd16454f2c..0000000000 --- a/doc/tutorials/core/mat-mask-operations/mat-mask-operations.rst +++ /dev/null @@ -1,137 +0,0 @@ -.. _maskOperationsFilter: - -Mask operations on matrices -*************************** - -Mask operations on matrices are quite simple. The idea is that we recalculate each pixels value in an image according to a mask matrix (also known as kernel). This mask holds values that will adjust how much influence neighboring pixels (and the current pixel) have on the new pixel value. From a mathematical point of view we make a weighted average, with our specified values. - -Our test case -============= - -Let us consider the issue of an image contrast enhancement method. Basically we want to apply for every pixel of the image the following formula: - -.. math:: - - I(i,j) = 5*I(i,j) - [ I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)] - - \iff I(i,j)*M, \text{where } - M = \bordermatrix{ _i\backslash ^j & -1 & 0 & +1 \cr - -1 & 0 & -1 & 0 \cr - 0 & -1 & 5 & -1 \cr - +1 & 0 & -1 & 0 \cr - } - -The first notation is by using a formula, while the second is a compacted version of the first by using a mask. You use the mask by putting the center of the mask matrix (in the upper case noted by the zero-zero index) on the pixel you want to calculate and sum up the pixel values multiplied with the overlapped matrix values. It's the same thing, however in case of large matrices the latter notation is a lot easier to look over. - -Now let us see how we can make this happen by using the basic pixel access method or by using the :filtering:`filter2D ` function. - -The Basic Method -================ - -Here's a function that will do this: - -.. code-block:: cpp - - void Sharpen(const Mat& myImage, Mat& Result) - { - CV_Assert(myImage.depth() == CV_8U); // accept only uchar images - - Result.create(myImage.size(), myImage.type()); - const int nChannels = myImage.channels(); - - for(int j = 1; j < myImage.rows - 1; ++j) - { - const uchar* previous = myImage.ptr(j - 1); - const uchar* current = myImage.ptr(j ); - const uchar* next = myImage.ptr(j + 1); - - uchar* output = Result.ptr(j); - - for(int i = nChannels; i < nChannels * (myImage.cols - 1); ++i) - { - *output++ = saturate_cast(5 * current[i] - -current[i - nChannels] - current[i + nChannels] - previous[i] - next[i]); - } - } - - Result.row(0).setTo(Scalar(0)); - Result.row(Result.rows - 1).setTo(Scalar(0)); - Result.col(0).setTo(Scalar(0)); - Result.col(Result.cols - 1).setTo(Scalar(0)); - } - -At first we make sure that the input images data is in unsigned char format. For this we use the :utilitysystemfunctions:`CV_Assert ` function that throws an error when the expression inside it is false. - -.. code-block:: cpp - - CV_Assert(myImage.depth() == CV_8U); // accept only uchar images - -We create an output image with the same size and the same type as our input. As you can see in the :ref:`How_Image_Stored_Memory` section, depending on the number of channels we may have one or more subcolumns. We will iterate through them via pointers so the total number of elements depends from this number. - -.. code-block:: cpp - - Result.create(myImage.size(), myImage.type()); - const int nChannels = myImage.channels(); - -We'll use the plain C [] operator to access pixels. Because we need to access multiple rows at the same time we'll acquire the pointers for each of them (a previous, a current and a next line). We need another pointer to where we're going to save the calculation. Then simply access the right items with the [] operator. For moving the output pointer ahead we simply increase this (with one byte) after each operation: - -.. code-block:: cpp - - for(int j = 1; j < myImage.rows - 1; ++j) - { - const uchar* previous = myImage.ptr(j - 1); - const uchar* current = myImage.ptr(j ); - const uchar* next = myImage.ptr(j + 1); - - uchar* output = Result.ptr(j); - - for(int i = nChannels; i < nChannels * (myImage.cols - 1); ++i) - { - *output++ = saturate_cast(5 * current[i] - -current[i - nChannels] - current[i + nChannels] - previous[i] - next[i]); - } - } - -On the borders of the image the upper notation results inexistent pixel locations (like minus one - minus one). In these points our formula is undefined. A simple solution is to not apply the kernel in these points and, for example, set the pixels on the borders to zeros: - -.. code-block:: cpp - - Result.row(0).setTo(Scalar(0)); // The top row - Result.row(Result.rows - 1).setTo(Scalar(0)); // The bottom row - Result.col(0).setTo(Scalar(0)); // The left column - Result.col(Result.cols - 1).setTo(Scalar(0)); // The right column - -The filter2D function -===================== - -Applying such filters are so common in image processing that in OpenCV there exist a function that will take care of applying the mask (also called a kernel in some places). For this you first need to define a *Mat* object that holds the mask: - -.. code-block:: cpp - - Mat kern = (Mat_(3,3) << 0, -1, 0, - -1, 5, -1, - 0, -1, 0); - -Then call the :filtering:`filter2D ` function specifying the input, the output image and the kernell to use: - -.. code-block:: cpp - - filter2D(I, K, I.depth(), kern); - -The function even has a fifth optional argument to specify the center of the kernel, and a sixth one for determining what to do in the regions where the operation is undefined (borders). Using this function has the advantage that it's shorter, less verbose and because there are some optimization techniques implemented it is usually faster than the *hand-coded method*. For example in my test while the second one took only 13 milliseconds the first took around 31 milliseconds. Quite some difference. - -For example: - -.. image:: images/resultMatMaskFilter2D.png - :alt: A sample output of the program - :align: center - -You can download this source code from :download:`here <../../../../samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp>` or look in the OpenCV source code libraries sample directory at :file:`samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp`. - -Check out an instance of running the program on our `YouTube channel `_ . - -.. raw:: html - -
- -
diff --git a/doc/tutorials/core/mat-mask-operations/mat_mask_operations.markdown b/doc/tutorials/core/mat-mask-operations/mat_mask_operations.markdown index e185d2803d..48b7b13a14 100644 --- a/doc/tutorials/core/mat-mask-operations/mat_mask_operations.markdown +++ b/doc/tutorials/core/mat-mask-operations/mat_mask_operations.markdown @@ -133,7 +133,7 @@ For example: ![](images/resultMatMaskFilter2D.png) You can download this source code from [here -](samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp) or look in the +](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp) or look in the OpenCV source code libraries sample directory at `samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp`. diff --git a/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown b/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown index c8de768fe9..68b1fae9e4 100644 --- a/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown +++ b/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown @@ -144,16 +144,13 @@ file by using the @ref cv::imwrite() function. However, for debugging purposes i convenient to see the actual values. You can do this using the \<\< operator of *Mat*. Be aware that this only works for two dimensional matrices. -@dontinclude cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - Although *Mat* works really well as an image container, it is also a general matrix class. Therefore, it is possible to create and manipulate multidimensional matrices. You can create a Mat object in multiple ways: - @ref cv::Mat::Mat Constructor - @skip Mat M(2 - @until cout + @snippet mat_the_basic_image_container.cpp constructor ![](images/MatBasicContainerOut1.png) @@ -162,7 +159,7 @@ object in multiple ways: Then we need to specify the data type to use for storing the elements and the number of channels per matrix point. To do this we have multiple definitions constructed according to the following convention: - @code{.cpp} + @code CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number] @endcode For instance, *CV_8UC3* means we use unsigned char types that are 8 bit long and each pixel has @@ -173,18 +170,15 @@ object in multiple ways: - Use C/C++ arrays and initialize via constructor - @skip int sz - @until Mat L + @snippet mat_the_basic_image_container.cpp init The upper example shows how to create a matrix with more than two dimensions. Specify its dimension, then pass a pointer containing the size for each dimension and the rest remains the same. - @ref cv::Mat::create function: - @code - M.create(4,4, CV_8UC(2)); - cout << "M = "<< endl << " " << M << endl << endl; - @endcode + + @snippet mat_the_basic_image_container.cpp create ![](images/MatBasicContainerOut2.png) @@ -194,30 +188,26 @@ object in multiple ways: - MATLAB style initializer: @ref cv::Mat::zeros , @ref cv::Mat::ones , @ref cv::Mat::eye . Specify size and data type to use: - @skip Mat E - @until cout + @snippet mat_the_basic_image_container.cpp matlab ![](images/MatBasicContainerOut3.png) - For small matrices you may use comma separated initializers: - @skip Mat C - @until cout + @snippet mat_the_basic_image_container.cpp comma ![](images/MatBasicContainerOut6.png) - Create a new header for an existing *Mat* object and @ref cv::Mat::clone or @ref cv::Mat::copyTo it. - @skip Mat RowClone - @until cout + @snippet mat_the_basic_image_container.cpp clone ![](images/MatBasicContainerOut7.png) @note You can fill out a matrix with random values using the @ref cv::randu() function. You need to give the lower and upper value for the random values: - @skip Mat R - @until randu + @snippet mat_the_basic_image_container.cpp random Output formatting @@ -227,25 +217,23 @@ In the above examples you could see the default formatting option. OpenCV, howev format your matrix output: - Default - @skipline (default) + @snippet mat_the_basic_image_container.cpp out-default ![](images/MatBasicContainerOut8.png) - Python - @skipline (python) + @snippet mat_the_basic_image_container.cpp out-python ![](images/MatBasicContainerOut16.png) - Comma separated values (CSV) - @skipline (csv) + @snippet mat_the_basic_image_container.cpp out-csv ![](images/MatBasicContainerOut10.png) - Numpy - @code - cout << "R (numpy) = " << endl << format(R, Formatter::FMT_NUMPY ) << endl << endl; - @endcode + @snippet mat_the_basic_image_container.cpp out-numpy ![](images/MatBasicContainerOut9.png) - C - @skipline (c) + @snippet mat_the_basic_image_container.cpp out-c ![](images/MatBasicContainerOut11.png) Output of other common items @@ -254,27 +242,23 @@ Output of other common items OpenCV offers support for output of other common OpenCV data structures too via the \<\< operator: - 2D Point - @skip Point2f P - @until cout + @snippet mat_the_basic_image_container.cpp out-point2 ![](images/MatBasicContainerOut12.png) - 3D Point - @skip Point3f P3f - @until cout + @snippet mat_the_basic_image_container.cpp out-point3 ![](images/MatBasicContainerOut13.png) - std::vector via cv::Mat - @skip vector v - @until cout + @snippet mat_the_basic_image_container.cpp out-vector ![](images/MatBasicContainerOut14.png) - std::vector of points - @skip vector vPoints - @until cout + @snippet mat_the_basic_image_container.cpp out-vector-points ![](images/MatBasicContainerOut15.png) Most of the samples here have been included in a small console application. You can download it from -[here](samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp) +[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp) or in the core section of the cpp samples. You can also find a quick video demonstration of this on diff --git a/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.rst b/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.rst deleted file mode 100644 index a3938c8726..0000000000 --- a/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.rst +++ /dev/null @@ -1,311 +0,0 @@ -.. _matTheBasicImageContainer: - -Mat - The Basic Image Container -******************************* - -Goal -==== - -We have multiple ways to acquire digital images from the real world: digital cameras, scanners, computed tomography, and magnetic resonance imaging to name a few. In every case what we (humans) see are images. However, when transforming this to our digital devices what we record are numerical values for each of the points of the image. - -.. image:: images/MatBasicImageForComputer.jpg - :alt: A matrix of the mirror of a car - :align: center - -For example in the above image you can see that the mirror of the car is nothing more than a matrix containing all the intensity values of the pixel points. How we get and store the pixels values may vary according to our needs, but in the end all images inside a computer world may be reduced to numerical matrices and other information describing the matrix itself. *OpenCV* is a computer vision library whose main focus is to process and manipulate this information. Therefore, the first thing you need to be familiar with is how OpenCV stores and handles images. - -*Mat* -===== - -OpenCV has been around since 2001. In those days the library was built around a *C* interface and to store the image in the memory they used a C structure called *IplImage*. This is the one you'll see in most of the older tutorials and educational materials. The problem with this is that it brings to the table all the minuses of the C language. The biggest issue is the manual memory management. It builds on the assumption that the user is responsible for taking care of memory allocation and deallocation. While this is not a problem with smaller programs, once your code base grows it will be more of a struggle to handle all this rather than focusing on solving your development goal. - -Luckily C++ came around and introduced the concept of classes making easier for the user through automatic memory management (more or less). The good news is that C++ is fully compatible with C so no compatibility issues can arise from making the change. Therefore, OpenCV 2.0 introduced a new C++ interface which offered a new way of doing things which means you do not need to fiddle with memory management, making your code concise (less to write, to achieve more). The main downside of the C++ interface is that many embedded development systems at the moment support only C. Therefore, unless you are targeting embedded platforms, there's no point to using the *old* methods (unless you're a masochist programmer and you're asking for trouble). - -The first thing you need to know about *Mat* is that you no longer need to manually allocate its memory and release it as soon as you do not need it. While doing this is still a possibility, most of the OpenCV functions will allocate its output data automatically. As a nice bonus if you pass on an already existing *Mat* object, which has already allocated the required space for the matrix, this will be reused. In other words we use at all times only as much memory as we need to perform the task. - -*Mat* is basically a class with two data parts: the matrix header (containing information such as the size of the matrix, the method used for storing, at which address is the matrix stored, and so on) and a pointer to the matrix containing the pixel values (taking any dimensionality depending on the method chosen for storing) . The matrix header size is constant, however the size of the matrix itself may vary from image to image and usually is larger by orders of magnitude. - -OpenCV is an image processing library. It contains a large collection of image processing functions. To solve a computational challenge, most of the time you will end up using multiple functions of the library. Because of this, passing images to functions is a common practice. We should not forget that we are talking about image processing algorithms, which tend to be quite computational heavy. The last thing we want to do is further decrease the speed of your program by making unnecessary copies of potentially *large* images. - -To tackle this issue OpenCV uses a reference counting system. The idea is that each *Mat* object has its own header, however the matrix may be shared between two instance of them by having their matrix pointers point to the same address. Moreover, the copy operators **will only copy the headers** and the pointer to the large matrix, not the data itself. - -.. code-block:: cpp - :linenos: - - Mat A, C; // creates just the header parts - A = imread(argv[1], IMREAD_COLOR); // here we'll know the method used (allocate matrix) - - Mat B(A); // Use the copy constructor - - C = A; // Assignment operator - -All the above objects, in the end, point to the same single data matrix. Their headers are different, however, and making a modification using any of them will affect all the other ones as well. In practice the different objects just provide different access method to the same underlying data. Nevertheless, their header parts are different. The real interesting part is that you can create headers which refer to only a subsection of the full data. For example, to create a region of interest (*ROI*) in an image you just create a new header with the new boundaries: - -.. code-block:: cpp - :linenos: - - Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle - Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries - -Now you may ask if the matrix itself may belong to multiple *Mat* objects who takes responsibility for cleaning it up when it's no longer needed. The short answer is: the last object that used it. This is handled by using a reference counting mechanism. Whenever somebody copies a header of a *Mat* object, a counter is increased for the matrix. Whenever a header is cleaned this counter is decreased. When the counter reaches zero the matrix too is freed. Sometimes you will want to copy the matrix itself too, so OpenCV provides the :basicstructures:`clone() ` and :basicstructures:`copyTo() ` functions. - -.. code-block:: cpp - :linenos: - - Mat F = A.clone(); - Mat G; - A.copyTo(G); - -Now modifying *F* or *G* will not affect the matrix pointed by the *Mat* header. What you need to remember from all this is that: - -.. container:: enumeratevisibleitemswithsquare - - * Output image allocation for OpenCV functions is automatic (unless specified otherwise). - * You do not need to think about memory management with OpenCVs C++ interface. - * The assignment operator and the copy constructor only copies the header. - * The underlying matrix of an image may be copied using the :basicstructures:`clone()` and :basicstructures:`copyTo() ` functions. - -*Storing* methods -================= - -This is about how you store the pixel values. You can select the color space and the data type used. The color space refers to how we combine color components in order to code a given color. The simplest one is the gray scale where the colors at our disposal are black and white. The combination of these allows us to create many shades of gray. - -For *colorful* ways we have a lot more methods to choose from. Each of them breaks it down to three or four basic components and we can use the combination of these to create the others. The most popular one is RGB, mainly because this is also how our eye builds up colors. Its base colors are red, green and blue. To code the transparency of a color sometimes a fourth element: alpha (A) is added. - -There are, however, many other color systems each with their own advantages: - -.. container:: enumeratevisibleitemswithsquare - - * RGB is the most common as our eyes use something similar, our display systems also compose colors using these. - * The HSV and HLS decompose colors into their hue, saturation and value/luminance components, which is a more natural way for us to describe colors. You might, for example, dismiss the last component, making your algorithm less sensible to the light conditions of the input image. - * YCrCb is used by the popular JPEG image format. - * CIE L*a*b* is a perceptually uniform color space, which comes handy if you need to measure the *distance* of a given color to another color. - -Each of the building components has their own valid domains. This leads to the data type used. How we store a component defines the control we have over its domain. The smallest data type possible is *char*, which means one byte or 8 bits. This may be unsigned (so can store values from 0 to 255) or signed (values from -127 to +127). Although in case of three components this already gives 16 million possible colors to represent (like in case of RGB) we may acquire an even finer control by using the float (4 byte = 32 bit) or double (8 byte = 64 bit) data types for each component. Nevertheless, remember that increasing the size of a component also increases the size of the whole picture in the memory. - -Creating a *Mat* object explicitly -================================== - -In the :ref:`Load_Save_Image` tutorial you have already learned how to write a matrix to an image file by using the :readwriteimage:`imwrite() ` function. However, for debugging purposes it's much more convenient to see the actual values. You can do this using the << operator of *Mat*. Be aware that this only works for two dimensional matrices. - -Although *Mat* works really well as an image container, it is also a general matrix class. Therefore, it is possible to create and manipulate multidimensional matrices. You can create a Mat object in multiple ways: - -.. container:: enumeratevisibleitemswithsquare - - + :basicstructures:`Mat() ` Constructor - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 27-28 - - .. image:: images/MatBasicContainerOut1.png - :alt: Demo image of the matrix output - :align: center - - For two dimensional and multichannel images we first define their size: row and column count wise. - - Then we need to specify the data type to use for storing the elements and the number of channels per matrix point. To do this we have multiple definitions constructed according to the following convention: - - .. code-block:: cpp - - CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number] - - For instance, *CV_8UC3* means we use unsigned char types that are 8 bit long and each pixel has three of these to form the three channels. This are predefined for up to four channel numbers. The :basicstructures:`Scalar ` is four element short vector. Specify this and you can initialize all matrix points with a custom value. If you need more you can create the type with the upper macro, setting the channel number in parenthesis as you can see below. - - + Use C/C++ arrays and initialize via constructor - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 35-36 - - The upper example shows how to create a matrix with more than two dimensions. Specify its dimension, then pass a pointer containing the size for each dimension and the rest remains the same. - - - + Create a header for an already existing IplImage pointer: - - .. code-block:: cpp - - IplImage* img = cvLoadImage("greatwave.png", 1); - Mat mtx(img); // convert IplImage* -> Mat - - + :basicstructures:`Create() ` function: - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 31-32 - - .. image:: images/MatBasicContainerOut2.png - :alt: Demo image of the matrix output - :align: center - - You cannot initialize the matrix values with this construction. It will only reallocate its matrix data memory if the new size will not fit into the old one. - - + MATLAB style initializer: :basicstructures:`zeros() `, :basicstructures:`ones() `, :basicstructures:`eye() `. Specify size and data type to use: - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 40-47 - - .. image:: images/MatBasicContainerOut3.png - :alt: Demo image of the matrix output - :align: center - - + For small matrices you may use comma separated initializers: - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 50-51 - - .. image:: images/MatBasicContainerOut6.png - :alt: Demo image of the matrix output - :align: center - - + Create a new header for an existing *Mat* object and :basicstructures:`clone() ` or :basicstructures:`copyTo() ` it. - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 53-54 - - .. image:: images/MatBasicContainerOut7.png - :alt: Demo image of the matrix output - :align: center - -.. note:: - - You can fill out a matrix with random values using the :operationsOnArrays:`randu() ` function. You need to give the lower and upper value for the random values: - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 57-58 - - -Output formatting -================= - -In the above examples you could see the default formatting option. OpenCV, however, allows you to format your matrix output: - -.. container:: enumeratevisibleitemswithsquare - - + Default - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 61 - - .. image:: images/MatBasicContainerOut8.png - :alt: Default Output - :align: center - - + Python - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 62 - - .. image:: images/MatBasicContainerOut16.png - :alt: Default Output - :align: center - - + Comma separated values (CSV) - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 64 - - .. image:: images/MatBasicContainerOut10.png - :alt: Default Output - :align: center - - + Numpy - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 63 - - .. image:: images/MatBasicContainerOut9.png - :alt: Default Output - :align: center - - + C - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 65 - - .. image:: images/MatBasicContainerOut11.png - :alt: Default Output - :align: center - -Output of other common items -============================ - -OpenCV offers support for output of other common OpenCV data structures too via the << operator: - -.. container:: enumeratevisibleitemswithsquare - - + 2D Point - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 67-68 - - .. image:: images/MatBasicContainerOut12.png - :alt: Default Output - :align: center - - - + 3D Point - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 70-71 - - .. image:: images/MatBasicContainerOut13.png - :alt: Default Output - :align: center - - + std::vector via cv::Mat - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 74-77 - - .. image:: images/MatBasicContainerOut14.png - :alt: Default Output - :align: center - - + std::vector of points - - .. literalinclude:: ../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp - :language: cpp - :tab-width: 4 - :lines: 79-83 - - .. image:: images/MatBasicContainerOut15.png - :alt: Default Output - :align: center - -Most of the samples here have been included in a small console application. You can download it from :download:`here <../../../../samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp>` or in the core section of the cpp samples. - -You can also find a quick video demonstration of this on `YouTube `_. - -.. raw:: html - -
- -
diff --git a/doc/tutorials/core/random_generator_and_text/random_generator_and_text.rst b/doc/tutorials/core/random_generator_and_text/random_generator_and_text.rst deleted file mode 100644 index c5f4fed474..0000000000 --- a/doc/tutorials/core/random_generator_and_text/random_generator_and_text.rst +++ /dev/null @@ -1,267 +0,0 @@ -.. _Drawing_2: - -Random generator and text with OpenCV -************************************* - -Goals -====== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the *Random Number generator class* (:rng:`RNG <>`) and how to get a random number from a uniform distribution. - * Display text on an OpenCV window by using the function :put_text:`putText <>` - -Code -===== - -.. container:: enumeratevisibleitemswithsquare - - * In the previous tutorial (:ref:`Drawing_1`) we drew diverse geometric figures, giving as input parameters such as coordinates (in the form of :point:`Points <>`), color, thickness, etc. You might have noticed that we gave specific values for these arguments. - - * In this tutorial, we intend to use *random* values for the drawing parameters. Also, we intend to populate our image with a big number of geometric figures. Since we will be initializing them in a random fashion, this process will be automatic and made by using *loops* . - - * This code is in your OpenCV sample folder. Otherwise you can grab it from `here `_ . - -Explanation -============ - -#. Let's start by checking out the *main* function. We observe that first thing we do is creating a *Random Number Generator* object (RNG): - - .. code-block:: cpp - - RNG rng( 0xFFFFFFFF ); - - RNG implements a random number generator. In this example, *rng* is a RNG element initialized with the value *0xFFFFFFFF* - -#. Then we create a matrix initialized to *zeros* (which means that it will appear as black), specifying its height, width and its type: - - .. code-block:: cpp - - /// Initialize a matrix filled with zeros - Mat image = Mat::zeros( window_height, window_width, CV_8UC3 ); - - /// Show it in a window during DELAY ms - imshow( window_name, image ); - -#. Then we proceed to draw crazy stuff. After taking a look at the code, you can see that it is mainly divided in 8 sections, defined as functions: - - .. code-block:: cpp - - /// Now, let's draw some lines - c = Drawing_Random_Lines(image, window_name, rng); - if( c != 0 ) return 0; - - /// Go on drawing, this time nice rectangles - c = Drawing_Random_Rectangles(image, window_name, rng); - if( c != 0 ) return 0; - - /// Draw some ellipses - c = Drawing_Random_Ellipses( image, window_name, rng ); - if( c != 0 ) return 0; - - /// Now some polylines - c = Drawing_Random_Polylines( image, window_name, rng ); - if( c != 0 ) return 0; - - /// Draw filled polygons - c = Drawing_Random_Filled_Polygons( image, window_name, rng ); - if( c != 0 ) return 0; - - /// Draw circles - c = Drawing_Random_Circles( image, window_name, rng ); - if( c != 0 ) return 0; - - /// Display text in random positions - c = Displaying_Random_Text( image, window_name, rng ); - if( c != 0 ) return 0; - - /// Displaying the big end! - c = Displaying_Big_End( image, window_name, rng ); - - All of these functions follow the same pattern, so we will analyze only a couple of them, since the same explanation applies for all. - -#. Checking out the function **Drawing_Random_Lines**: - - .. code-block:: cpp - - int Drawing_Random_Lines( Mat image, char* window_name, RNG rng ) - { - int lineType = 8; - Point pt1, pt2; - - for( int i = 0; i < NUMBER; i++ ) - { - pt1.x = rng.uniform( x_1, x_2 ); - pt1.y = rng.uniform( y_1, y_2 ); - pt2.x = rng.uniform( x_1, x_2 ); - pt2.y = rng.uniform( y_1, y_2 ); - - line( image, pt1, pt2, randomColor(rng), rng.uniform(1, 10), 8 ); - imshow( window_name, image ); - if( waitKey( DELAY ) >= 0 ) - { return -1; } - } - return 0; - } - - We can observe the following: - - * The *for* loop will repeat **NUMBER** times. Since the function :line:`line <>` is inside this loop, that means that **NUMBER** lines will be generated. - * The line extremes are given by *pt1* and *pt2*. For *pt1* we can see that: - - .. code-block:: cpp - - pt1.x = rng.uniform( x_1, x_2 ); - pt1.y = rng.uniform( y_1, y_2 ); - - * We know that **rng** is a *Random number generator* object. In the code above we are calling **rng.uniform(a,b)**. This generates a radombly uniformed distribution between the values **a** and **b** (inclusive in **a**, exclusive in **b**). - - * From the explanation above, we deduce that the extremes *pt1* and *pt2* will be random values, so the lines positions will be quite impredictable, giving a nice visual effect (check out the Result section below). - - * As another observation, we notice that in the :line:`line <>` arguments, for the *color* input we enter: - - .. code-block:: cpp - - randomColor(rng) - - Let's check the function implementation: - - .. code-block:: cpp - - static Scalar randomColor( RNG& rng ) - { - int icolor = (unsigned) rng; - return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 ); - } - - As we can see, the return value is an *Scalar* with 3 randomly initialized values, which are used as the *R*, *G* and *B* parameters for the line color. Hence, the color of the lines will be random too! - -#. The explanation above applies for the other functions generating circles, ellipses, polygones, etc. The parameters such as *center* and *vertices* are also generated randomly. - -#. Before finishing, we also should take a look at the functions *Display_Random_Text* and *Displaying_Big_End*, since they both have a few interesting features: - -#. **Display_Random_Text:** - - .. code-block:: cpp - - int Displaying_Random_Text( Mat image, char* window_name, RNG rng ) - { - int lineType = 8; - - for ( int i = 1; i < NUMBER; i++ ) - { - Point org; - org.x = rng.uniform(x_1, x_2); - org.y = rng.uniform(y_1, y_2); - - putText( image, "Testing text rendering", org, rng.uniform(0,8), - rng.uniform(0,100)*0.05+0.1, randomColor(rng), rng.uniform(1, 10), lineType); - - imshow( window_name, image ); - if( waitKey(DELAY) >= 0 ) - { return -1; } - } - - return 0; - } - - Everything looks familiar but the expression: - - .. code-block:: cpp - - putText( image, "Testing text rendering", org, rng.uniform(0,8), - rng.uniform(0,100)*0.05+0.1, randomColor(rng), rng.uniform(1, 10), lineType); - - - So, what does the function :put_text:`putText <>` do? In our example: - - .. container:: enumeratevisibleitemswithsquare - - * Draws the text **"Testing text rendering"** in **image** - * The bottom-left corner of the text will be located in the Point **org** - * The font type is a random integer value in the range: :math:`[0, 8>`. - * The scale of the font is denoted by the expression **rng.uniform(0, 100)x0.05 + 0.1** (meaning its range is: :math:`[0.1, 5.1>`) - * The text color is random (denoted by **randomColor(rng)**) - * The text thickness ranges between 1 and 10, as specified by **rng.uniform(1,10)** - - As a result, we will get (analagously to the other drawing functions) **NUMBER** texts over our image, in random locations. - -#. **Displaying_Big_End** - - .. code-block:: cpp - - int Displaying_Big_End( Mat image, char* window_name, RNG rng ) - { - Size textsize = getTextSize("OpenCV forever!", FONT_HERSHEY_COMPLEX, 3, 5, 0); - Point org((window_width - textsize.width)/2, (window_height - textsize.height)/2); - int lineType = 8; - - Mat image2; - - for( int i = 0; i < 255; i += 2 ) - { - image2 = image - Scalar::all(i); - putText( image2, "OpenCV forever!", org, FONT_HERSHEY_COMPLEX, 3, - Scalar(i, i, 255), 5, lineType ); - - imshow( window_name, image2 ); - if( waitKey(DELAY) >= 0 ) - { return -1; } - } - - return 0; - } - - Besides the function **getTextSize** (which gets the size of the argument text), the new operation we can observe is inside the *foor* loop: - - .. code-block:: cpp - - image2 = image - Scalar::all(i) - - So, **image2** is the substraction of **image** and **Scalar::all(i)**. In fact, what happens here is that every pixel of **image2** will be the result of substracting every pixel of **image** minus the value of **i** (remember that for each pixel we are considering three values such as R, G and B, so each of them will be affected) - - Also remember that the substraction operation *always* performs internally a **saturate** operation, which means that the result obtained will always be inside the allowed range (no negative and between 0 and 255 for our example). - - -Result -======== - -As you just saw in the Code section, the program will sequentially execute diverse drawing functions, which will produce: - -#. First a random set of *NUMBER* lines will appear on screen such as it can be seen in this screenshot: - - .. image:: images/Drawing_2_Tutorial_Result_0.jpg - :alt: Drawing Tutorial 2 - Final Result 0 - :align: center - -#. Then, a new set of figures, these time *rectangles* will follow. - -#. Now some ellipses will appear, each of them with random position, size, thickness and arc length: - - .. image:: images/Drawing_2_Tutorial_Result_2.jpg - :alt: Drawing Tutorial 2 - Final Result 2 - :align: center - -#. Now, *polylines* with 03 segments will appear on screen, again in random configurations. - - .. image:: images/Drawing_2_Tutorial_Result_3.jpg - :alt: Drawing Tutorial 2 - Final Result 3 - :align: center - -#. Filled polygons (in this example triangles) will follow. - -#. The last geometric figure to appear: circles! - - .. image:: images/Drawing_2_Tutorial_Result_5.jpg - :alt: Drawing Tutorial 2 - Final Result 5 - :align: center - -#. Near the end, the text *"Testing Text Rendering"* will appear in a variety of fonts, sizes, colors and positions. - -#. And the big end (which by the way expresses a big truth too): - - .. image:: images/Drawing_2_Tutorial_Result_big.jpg - :alt: Drawing Tutorial 2 - Final Result 7 - :align: center diff --git a/doc/tutorials/core/table_of_content_core/table_of_content_core.markdown b/doc/tutorials/core/table_of_content_core.markdown similarity index 100% rename from doc/tutorials/core/table_of_content_core/table_of_content_core.markdown rename to doc/tutorials/core/table_of_content_core.markdown diff --git a/doc/tutorials/core/table_of_content_core/table_of_content_core.rst b/doc/tutorials/core/table_of_content_core/table_of_content_core.rst deleted file mode 100644 index ea5756da23..0000000000 --- a/doc/tutorials/core/table_of_content_core/table_of_content_core.rst +++ /dev/null @@ -1,240 +0,0 @@ -.. _Table-Of-Content-Core: - -*core* module. The Core Functionality ------------------------------------------------------------ - -Here you will learn the about the basic building blocks of the library. A must read and know for understanding how to manipulate the images on a pixel level. - -.. include:: ../../definitions/tocDefinitions.rst - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |MatBasicIma| **Title:** :ref:`matTheBasicImageContainer` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - You will learn how to store images in the memory and how to print out their content to the console. - - =============== ====================================================== - - .. |MatBasicIma| image:: images/matTheBasicImageStructure.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |HowScanImag| **Title:** :ref:`howToScanImagesOpenCV` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - You'll find out how to scan images (go through each of the image pixels) with OpenCV. Bonus: time measurement with OpenCV. - - =============== ====================================================== - - .. |HowScanImag| image:: images/howToScanImages.jpg - :height: 90pt - :width: 90pt - - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |HowFilterIm| **Title:** :ref:`maskOperationsFilter` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - You'll find out how to scan images with neighbor access and use the :filtering:`filter2D ` function to apply kernel filters on images. - - =============== ====================================================== - - .. |HowFilterIm| image:: images/matMaskFilter2DOp.png - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |Beginners_4| **Title:** :ref:`Adding_Images` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to blend two images! - - =============== ====================================================== - - .. |Beginners_4| image:: images/Adding_Images_Tutorial_Result_0.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ==================================================== - |Bas_Lin_Tran| **Title:** :ref:`Basic_Linear_Transform` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to change our image appearance! - - =============== ==================================================== - - .. |Bas_Lin_Tran| image:: images/Basic_Linear_Transform_Tutorial_Result_0.jpg - :height: 90pt - :width: 90pt - - - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |Beginners_6| **Title:** :ref:`Drawing_1` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to draw simple geometry with OpenCV! - - =============== ====================================================== - - .. |Beginners_6| image:: images/Drawing_1_Tutorial_Result_0.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |Beginners_7| **Title:** :ref:`Drawing_2` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will draw some *fancy-looking* stuff using OpenCV! - - =============== ====================================================== - - .. |Beginners_7| image:: images/Drawing_2_Tutorial_Result_7.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |DiscFourTr| **Title:** :ref:`discretFourierTransform` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - You will see how and why use the Discrete Fourier transformation with OpenCV. - - =============== ====================================================== - - .. |DiscFourTr| image:: images/discrete_fourier_transform.png - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |FileIOXMLYAML| **Title:** :ref:`fileInputOutputXMLYAML` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - You will see how to use the :xmlymlpers:`FileStorage ` data structure of OpenCV to write and read data to XML or YAML file format. - - =============== ====================================================== - - .. |FileIOXMLYAML| image:: images/file_input_output_with_xml_yml.png - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |InterOOpenCV1| **Title:** :ref:`InteroperabilityWithOpenCV1` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - Did you used OpenCV before its 2.0 version? Do you wanna know what happened with your library with 2.0? Don't you know how to convert your old OpenCV programs to the new C++ interface? Look here to shed light on all this questions. - - =============== ====================================================== - - .. |InterOOpenCV1| image:: images/interopOpenCV1.png - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |IPPIma| **Title:** :ref:`howToUseIPPAconversion` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_ElenaG| - - You will see how to use the IPP Async with OpenCV. - - =============== ====================================================== - - .. |IPPIma| image:: images/How_To_Use_IPPA.jpg - :height: 90pt - :width: 90pt - .. |Author_ElenaG| unicode:: Elena U+0020 Gvozdeva - -.. raw:: latex - - \pagebreak - -.. toctree:: - :hidden: - - ../mat_the_basic_image_container/mat_the_basic_image_container - ../how_to_scan_images/how_to_scan_images - ../mat-mask-operations/mat-mask-operations - ../adding_images/adding_images - ../basic_linear_transform/basic_linear_transform - ../basic_geometric_drawing/basic_geometric_drawing - ../random_generator_and_text/random_generator_and_text - ../discrete_fourier_transform/discrete_fourier_transform - ../file_input_output_with_xml_yml/file_input_output_with_xml_yml - ../interoperability_with_OpenCV_1/interoperability_with_OpenCV_1 - ../how_to_use_ippa_conversion/how_to_use_ippa_conversion diff --git a/doc/tutorials/definitions/README.txt b/doc/tutorials/definitions/README.txt deleted file mode 100644 index a598a95dd7..0000000000 --- a/doc/tutorials/definitions/README.txt +++ /dev/null @@ -1 +0,0 @@ -Include in this directory only defintion files. None of the reST files entered here will be parsed by the Sphinx Builder. diff --git a/doc/tutorials/definitions/noContent.rst b/doc/tutorials/definitions/noContent.rst deleted file mode 100644 index 50d9cd244b..0000000000 --- a/doc/tutorials/definitions/noContent.rst +++ /dev/null @@ -1,3 +0,0 @@ - -.. note:: - Unfortunetly we have no tutorials into this section. And you can help us with that, since OpenCV is a community effort. If you have a tutorial suggestion or you have written a tutorial yourself (or coded a sample code) that you would like to see here, please contact follow these instructions: :how_to_contribute:`How to contribute <>`. diff --git a/doc/tutorials/definitions/tocDefinitions.rst b/doc/tutorials/definitions/tocDefinitions.rst deleted file mode 100644 index 73387bac1b..0000000000 --- a/doc/tutorials/definitions/tocDefinitions.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. |Author_AnaH| unicode:: Ana U+0020 Huam U+00E1 n -.. |Author_BernatG| unicode:: Bern U+00E1 t U+0020 G U+00E1 bor -.. |Author_AndreyK| unicode:: Andrey U+0020 Kamaev -.. |Author_LeonidBLB| unicode:: Leonid U+0020 Beynenson -.. |Author_VsevolodG| unicode:: Vsevolod U+0020 Glumov -.. |Author_VictorE| unicode:: Victor U+0020 Eruhimov -.. |Author_ArtemM| unicode:: Artem U+0020 Myagkov -.. |Author_FernandoI| unicode:: Fernando U+0020 Iglesias U+0020 Garc U+00ED a -.. |Author_EduardF| unicode:: Eduard U+0020 Feicho -.. |Author_AlexB| unicode:: Alexandre U+0020 Benoit -.. |Author_EricCh| unicode:: Eric U+0020 Christiansen -.. |Author_AndreyP| unicode:: Andrey U+0020 Pavlenko -.. |Author_AlexS| unicode:: Alexander U+0020 Smorkalov -.. |Author_MimmoC| unicode:: Mimmo U+0020 Cosenza -.. |Author_BarisD| unicode:: Bar U+0131 U+015F U+0020 Evrim U+0020 Demir U+00F6 z -.. |Author_DomenicoB| unicode:: Domenico U+0020 Daniele U+0020 Bloisi -.. |Author_MarvinS| unicode:: Marvin U+0020 Smith diff --git a/doc/tutorials/features2d/akaze_matching/akaze_matching.rst b/doc/tutorials/features2d/akaze_matching/akaze_matching.rst deleted file mode 100644 index 4007d653da..0000000000 --- a/doc/tutorials/features2d/akaze_matching/akaze_matching.rst +++ /dev/null @@ -1,160 +0,0 @@ -.. _akazeMatching: - - -AKAZE local features matching -****************************** - -Introduction ------------------- - -In this tutorial we will learn how to use [AKAZE]_ local features to detect and match keypoints on two images. - -We will find keypoints on a pair of images with given homography matrix, -match them and count the number of inliers (i. e. matches that fit in the given homography). - -You can find expanded version of this example here: https://github.com/pablofdezalc/test_kaze_akaze_opencv - -.. [AKAZE] Fast Explicit Diffusion for Accelerated Features in Nonlinear Scale Spaces. Pablo F. Alcantarilla, Jesús Nuevo and Adrien Bartoli. In British Machine Vision Conference (BMVC), Bristol, UK, September 2013. - -Data ------------------- -We are going to use images 1 and 3 from *Graffity* sequence of Oxford dataset. - -.. image:: images/graf.png - :height: 200pt - :width: 320pt - :alt: Graffity - :align: center - -Homography is given by a 3 by 3 matrix: - -.. code-block:: none - - 7.6285898e-01 -2.9922929e-01 2.2567123e+02 - 3.3443473e-01 1.0143901e+00 -7.6999973e+01 - 3.4663091e-04 -1.4364524e-05 1.0000000e+00 - -You can find the images (*graf1.png*, *graf3.png*) and homography (*H1to3p.xml*) in *opencv/samples/cpp*. - -Source Code -=========== -.. literalinclude:: ../../../../samples/cpp/tutorial_code/features2D/AKAZE_match.cpp - :language: cpp - :linenos: - :tab-width: 4 - -Explanation -=========== - -#. **Load images and homography** - - .. code-block:: cpp - - Mat img1 = imread("graf1.png", IMREAD_GRAYSCALE); - Mat img2 = imread("graf3.png", IMREAD_GRAYSCALE); - - Mat homography; - FileStorage fs("H1to3p.xml", FileStorage::READ); - fs.getFirstTopLevelNode() >> homography; - - We are loading grayscale images here. Homography is stored in the xml created with FileStorage. - -#. **Detect keypoints and compute descriptors using AKAZE** - - .. code-block:: cpp - - vector kpts1, kpts2; - Mat desc1, desc2; - - AKAZE akaze; - akaze(img1, noArray(), kpts1, desc1); - akaze(img2, noArray(), kpts2, desc2); - - We create AKAZE object and use it's *operator()* functionality. Since we don't need the *mask* parameter, *noArray()* is used. - -#. **Use brute-force matcher to find 2-nn matches** - - .. code-block:: cpp - - BFMatcher matcher(NORM_HAMMING); - vector< vector > nn_matches; - matcher.knnMatch(desc1, desc2, nn_matches, 2); - - We use Hamming distance, because AKAZE uses binary descriptor by default. - -#. **Use 2-nn matches to find correct keypoint matches** - - .. code-block:: cpp - - for(size_t i = 0; i < nn_matches.size(); i++) { - DMatch first = nn_matches[i][0]; - float dist1 = nn_matches[i][0].distance; - float dist2 = nn_matches[i][1].distance; - - if(dist1 < nn_match_ratio * dist2) { - matched1.push_back(kpts1[first.queryIdx]); - matched2.push_back(kpts2[first.trainIdx]); - } - } - - If the closest match is *ratio* closer than the second closest one, then the match is correct. - -#. **Check if our matches fit in the homography model** - - .. code-block:: cpp - - for(int i = 0; i < matched1.size(); i++) { - Mat col = Mat::ones(3, 1, CV_64F); - col.at(0) = matched1[i].pt.x; - col.at(1) = matched1[i].pt.y; - - col = homography * col; - col /= col.at(2); - float dist = sqrt( pow(col.at(0) - matched2[i].pt.x, 2) + - pow(col.at(1) - matched2[i].pt.y, 2)); - - if(dist < inlier_threshold) { - int new_i = inliers1.size(); - inliers1.push_back(matched1[i]); - inliers2.push_back(matched2[i]); - good_matches.push_back(DMatch(new_i, new_i, 0)); - } - } - - If the distance from first keypoint's projection to the second keypoint is less than threshold, then it it fits in the homography. - - We create a new set of matches for the inliers, because it is required by the drawing function. - -#. **Output results** - - .. code-block:: cpp - - Mat res; - drawMatches(img1, inliers1, img2, inliers2, good_matches, res); - imwrite("res.png", res); - ... - - Here we save the resulting image and print some statistics. - -Results -======= - -Found matches --------------- - -.. image:: images/res.png - :height: 200pt - :width: 320pt - :alt: Matches - :align: center - -A-KAZE Matching Results --------------------------- - -.. code-block:: none - - Keypoints 1 2943 - Keypoints 2 3511 - Matches 447 - Inliers 308 - Inlier Ratio 0.689038 diff --git a/doc/tutorials/features2d/akaze_tracking/akaze_tracking.rst b/doc/tutorials/features2d/akaze_tracking/akaze_tracking.rst deleted file mode 100644 index 9d45429e87..0000000000 --- a/doc/tutorials/features2d/akaze_tracking/akaze_tracking.rst +++ /dev/null @@ -1,155 +0,0 @@ -.. _akazeTracking: - - -AKAZE and ORB planar tracking -****************************** - -Introduction ------------------- - -In this tutorial we will compare *AKAZE* and *ORB* local features -using them to find matches between video frames and track object movements. - -The algorithm is as follows: - -* Detect and describe keypoints on the first frame, manually set object boundaries -* For every next frame: - - #. Detect and describe keypoints - #. Match them using bruteforce matcher - #. Estimate homography transformation using RANSAC - #. Filter inliers from all the matches - #. Apply homography transformation to the bounding box to find the object - #. Draw bounding box and inliers, compute inlier ratio as evaluation metric - -.. image:: images/frame.png - :height: 480pt - :width: 640pt - :alt: Result frame example - :align: center - -Data -=========== -To do the tracking we need a video and object position on the first frame. - -You can download our example video and data from `here `_. - -To run the code you have to specify input and output video path and object bounding box. - -.. code-block:: none - - ./planar_tracking blais.mp4 result.avi blais_bb.xml.gz - -Source Code -=========== -.. literalinclude:: ../../../../samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp - :language: cpp - :linenos: - :tab-width: 4 - -Explanation -=========== - -Tracker class --------------- - - This class implements algorithm described abobve - using given feature detector and descriptor matcher. - -* **Setting up the first frame** - - .. code-block:: cpp - - void Tracker::setFirstFrame(const Mat frame, vector bb, string title, Stats& stats) - { - first_frame = frame.clone(); - (*detector)(first_frame, noArray(), first_kp, first_desc); - stats.keypoints = (int)first_kp.size(); - drawBoundingBox(first_frame, bb); - putText(first_frame, title, Point(0, 60), FONT_HERSHEY_PLAIN, 5, Scalar::all(0), 4); - object_bb = bb; - } - - We compute and store keypoints and descriptors from the first frame and prepare it for the output. - - We need to save number of detected keypoints to make sure both detectors locate roughly the same number of those. - -* **Processing frames** - - #. Locate keypoints and compute descriptors - - .. code-block:: cpp - - (*detector)(frame, noArray(), kp, desc); - - To find matches between frames we have to locate the keypoints first. - - In this tutorial detectors are set up to find about 1000 keypoints on each frame. - - #. Use 2-nn matcher to find correspondences - - .. code-block:: cpp - - matcher->knnMatch(first_desc, desc, matches, 2); - for(unsigned i = 0; i < matches.size(); i++) { - if(matches[i][0].distance < nn_match_ratio * matches[i][1].distance) { - matched1.push_back(first_kp[matches[i][0].queryIdx]); - matched2.push_back( kp[matches[i][0].trainIdx]); - } - } - - If the closest match is *nn_match_ratio* closer than the second closest one, then it's a match. - - 2. Use *RANSAC* to estimate homography transformation - - .. code-block:: cpp - - homography = findHomography(Points(matched1), Points(matched2), - RANSAC, ransac_thresh, inlier_mask); - - If there are at least 4 matches we can use random sample consensus to estimate image transformation. - - 3. Save the inliers - - .. code-block:: cpp - - for(unsigned i = 0; i < matched1.size(); i++) { - if(inlier_mask.at(i)) { - int new_i = static_cast(inliers1.size()); - inliers1.push_back(matched1[i]); - inliers2.push_back(matched2[i]); - inlier_matches.push_back(DMatch(new_i, new_i, 0)); - } - } - - Since *findHomography* computes the inliers we only have to save the chosen points and matches. - - 4. Project object bounding box - - .. code-block:: cpp - - perspectiveTransform(object_bb, new_bb, homography); - - If there is a reasonable number of inliers we can use estimated transformation to locate the object. - -Results -======= -You can watch the resulting `video on youtube `_. - -*AKAZE* statistics: - - .. code-block:: none - - Matches 626 - Inliers 410 - Inlier ratio 0.58 - Keypoints 1117 - -*ORB* statistics: - - .. code-block:: none - - Matches 504 - Inliers 319 - Inlier ratio 0.56 - Keypoints 1112 diff --git a/doc/tutorials/features2d/detection_of_planar_objects/detection_of_planar_objects.rst b/doc/tutorials/features2d/detection_of_planar_objects/detection_of_planar_objects.rst deleted file mode 100644 index 5075be3c03..0000000000 --- a/doc/tutorials/features2d/detection_of_planar_objects/detection_of_planar_objects.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. _detectionOfPlanarObjects: - -Detection of planar objects -*************************** - -.. highlight:: cpp - -The goal of this tutorial is to learn how to use *features2d* and *calib3d* modules for detecting known planar objects in scenes. - -*Test data*: use images in your data folder, for instance, ``box.png`` and ``box_in_scene.png``. - -#. - Create a new console project. Read two input images. :: - - Mat img1 = imread(argv[1], IMREAD_GRAYSCALE); - Mat img2 = imread(argv[2], IMREAD_GRAYSCALE); - -#. - Detect keypoints in both images and compute descriptors for each of the keypoints. :: - - // detecting keypoints - Ptr surf = SURF::create(); - vector keypoints1; - Mat descriptors1; - surf->detectAndCompute(img1, Mat(), keypoints1, descriptors1); - - ... // do the same for the second image - -#. - Now, find the closest matches between descriptors from the first image to the second: :: - - // matching descriptors - BruteForceMatcher > matcher; - vector matches; - matcher.match(descriptors1, descriptors2, matches); - -#. - Visualize the results: :: - - // drawing the results - namedWindow("matches", 1); - Mat img_matches; - drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches); - imshow("matches", img_matches); - waitKey(0); - -#. - Find the homography transformation between two sets of points: :: - - vector points1, points2; - // fill the arrays with the points - .... - Mat H = findHomography(Mat(points1), Mat(points2), RANSAC, ransacReprojThreshold); - - -#. - Create a set of inlier matches and draw them. Use perspectiveTransform function to map points with homography: - - Mat points1Projected; - perspectiveTransform(Mat(points1), points1Projected, H); - -#. - Use ``drawMatches`` for drawing inliers. diff --git a/doc/tutorials/features2d/feature_description/feature_description.rst b/doc/tutorials/features2d/feature_description/feature_description.rst deleted file mode 100644 index 6752dd4a9e..0000000000 --- a/doc/tutorials/features2d/feature_description/feature_description.rst +++ /dev/null @@ -1,97 +0,0 @@ -.. _feature_description: - -Feature Description -******************* - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the :descriptor_extractor:`DescriptorExtractor<>` interface in order to find the feature vector correspondent to the keypoints. Specifically: - - * Use :surf_descriptor_extractor:`SurfDescriptorExtractor<>` and its function :descriptor_extractor:`compute<>` to perform the required calculations. - * Use a :brute_force_matcher:`BFMatcher<>` to match the features vector - * Use the function :draw_matches:`drawMatches<>` to draw the detected matches. - - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. - -.. code-block:: cpp - - #include - #include - #include "opencv2/core.hpp" - #include "opencv2/features2d.hpp" - #include "opencv2/highgui.hpp" - #include "opencv2/xfeatures2d.hpp" - - using namespace cv; - using namespace cv::xfeatures2d; - - void readme(); - - /* @function main */ - int main( int argc, char** argv ) - { - if( argc != 3 ) - { return -1; } - - Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE ); - Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE ); - - if( !img_1.data || !img_2.data ) - { return -1; } - - //-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors - int minHessian = 400; - - Ptr detector = SURF::create(); - detector->setMinHessian(minHessian); - - std::vector keypoints_1, keypoints_2; - Mat descriptors_1, descriptors_2; - - detector->detectAndCompute( img_1, keypoints_1, descriptors_1 ); - detector->detectAndCompute( img_2, keypoints_2, descriptors_2 ); - - //-- Step 2: Matching descriptor vectors with a brute force matcher - BFMatcher matcher(NORM_L2); - std::vector< DMatch > matches; - matcher.match( descriptors_1, descriptors_2, matches ); - - //-- Draw matches - Mat img_matches; - drawMatches( img_1, keypoints_1, img_2, keypoints_2, matches, img_matches ); - - //-- Show detected matches - imshow("Matches", img_matches ); - - waitKey(0); - - return 0; - } - - /* @function readme */ - void readme() - { std::cout << " Usage: ./SURF_descriptor " << std::endl; } - -Explanation -============ - -Result -====== - -#. Here is the result after applying the BruteForce matcher between the two original images: - - .. image:: images/Feature_Description_BruteForce_Result.jpg - :align: center - :height: 200pt diff --git a/doc/tutorials/features2d/feature_detection/feature_detection.rst b/doc/tutorials/features2d/feature_detection/feature_detection.rst deleted file mode 100644 index 24684bfe3c..0000000000 --- a/doc/tutorials/features2d/feature_detection/feature_detection.rst +++ /dev/null @@ -1,98 +0,0 @@ -.. _feature_detection: - -Feature Detection -****************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the :feature_detector:`FeatureDetector<>` interface in order to find interest points. Specifically: - - * Use the :surf_feature_detector:`SurfFeatureDetector<>` and its function :feature_detector_detect:`detect<>` to perform the detection process - * Use the function :draw_keypoints:`drawKeypoints<>` to draw the detected keypoints - - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. - -.. code-block:: cpp - - #include - #include - #include "opencv2/core.hpp" - #include "opencv2/features2d.hpp" - #include "opencv2/xfeatures2d.hpp" - #include "opencv2/highgui.hpp" - - using namespace cv; - using namespace cv::xfeatures2d; - - void readme(); - - /* @function main */ - int main( int argc, char** argv ) - { - if( argc != 3 ) - { readme(); return -1; } - - Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE ); - Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE ); - - if( !img_1.data || !img_2.data ) - { std::cout<< " --(!) Error reading images " << std::endl; return -1; } - - //-- Step 1: Detect the keypoints using SURF Detector - int minHessian = 400; - - Ptr detector = SURF::create( minHessian ); - - std::vector keypoints_1, keypoints_2; - - detector->detect( img_1, keypoints_1 ); - detector->detect( img_2, keypoints_2 ); - - //-- Draw keypoints - Mat img_keypoints_1; Mat img_keypoints_2; - - drawKeypoints( img_1, keypoints_1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT ); - drawKeypoints( img_2, keypoints_2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT ); - - //-- Show detected (drawn) keypoints - imshow("Keypoints 1", img_keypoints_1 ); - imshow("Keypoints 2", img_keypoints_2 ); - - waitKey(0); - - return 0; - } - - /* @function readme */ - void readme() - { std::cout << " Usage: ./SURF_detector " << std::endl; } - -Explanation -============ - -Result -====== - -#. Here is the result of the feature detection applied to the first image: - - .. image:: images/Feature_Detection_Result_a.jpg - :align: center - :height: 125pt - -#. And here is the result for the second image: - - .. image:: images/Feature_Detection_Result_b.jpg - :align: center - :height: 200pt diff --git a/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.rst b/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.rst deleted file mode 100644 index ff16f80af9..0000000000 --- a/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.rst +++ /dev/null @@ -1,149 +0,0 @@ -.. _feature_flann_matcher: - -Feature Matching with FLANN -**************************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the :flann_based_matcher:`FlannBasedMatcher<>` interface in order to perform a quick and efficient matching by using the :flann:`FLANN<>` ( *Fast Approximate Nearest Neighbor Search Library* ) - - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. - -.. code-block:: cpp - - /* - * @file SURF_FlannMatcher - * @brief SURF detector + descriptor + FLANN Matcher - * @author A. Huaman - */ - - #include - #include - #include - #include - #include "opencv2/core.hpp" - #include "opencv2/features2d.hpp" - #include "opencv2/imgcodecs.hpp" - #include "opencv2/highgui.hpp" - #include "opencv2/xfeatures2d.hpp" - - using namespace std; - using namespace cv; - using namespace cv::xfeatures2d; - - void readme(); - - /* - * @function main - * @brief Main function - */ - int main( int argc, char** argv ) - { - if( argc != 3 ) - { readme(); return -1; } - - Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE ); - Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE ); - - if( !img_1.data || !img_2.data ) - { std::cout<< " --(!) Error reading images " << std::endl; return -1; } - - //-- Step 1: Detect the keypoints using SURF Detector - int minHessian = 400; - - SurfFeatureDetector detector( minHessian ); - - std::vector keypoints_1, keypoints_2; - - detector.detect( img_1, keypoints_1 ); - detector.detect( img_2, keypoints_2 ); - - //-- Step 2: Calculate descriptors (feature vectors) - SurfDescriptorExtractor extractor; - - Mat descriptors_1, descriptors_2; - - extractor.compute( img_1, keypoints_1, descriptors_1 ); - extractor.compute( img_2, keypoints_2, descriptors_2 ); - - //-- Step 3: Matching descriptor vectors using FLANN matcher - FlannBasedMatcher matcher; - std::vector< DMatch > matches; - matcher.match( descriptors_1, descriptors_2, matches ); - - double max_dist = 0; double min_dist = 100; - - //-- Quick calculation of max and min distances between keypoints - for( int i = 0; i < descriptors_1.rows; i++ ) - { double dist = matches[i].distance; - if( dist < min_dist ) min_dist = dist; - if( dist > max_dist ) max_dist = dist; - } - - printf("-- Max dist : %f \n", max_dist ); - printf("-- Min dist : %f \n", min_dist ); - - //-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist, - //-- or a small arbitary value ( 0.02 ) in the event that min_dist is very - //-- small) - //-- PS.- radiusMatch can also be used here. - std::vector< DMatch > good_matches; - - for( int i = 0; i < descriptors_1.rows; i++ ) - { if( matches[i].distance <= max(2*min_dist, 0.02) ) - { good_matches.push_back( matches[i]); } - } - - //-- Draw only "good" matches - Mat img_matches; - drawMatches( img_1, keypoints_1, img_2, keypoints_2, - good_matches, img_matches, Scalar::all(-1), Scalar::all(-1), - vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); - - //-- Show detected matches - imshow( "Good Matches", img_matches ); - - for( int i = 0; i < (int)good_matches.size(); i++ ) - { printf( "-- Good Match [%d] Keypoint 1: %d -- Keypoint 2: %d \n", i, good_matches[i].queryIdx, good_matches[i].trainIdx ); } - - waitKey(0); - - return 0; - } - - /* - * @function readme - */ - void readme() - { std::cout << " Usage: ./SURF_FlannMatcher " << std::endl; } - - -Explanation -============ - -Result -====== - -#. Here is the result of the feature detection applied to the first image: - - .. image:: images/Featur_FlannMatcher_Result.jpg - :align: center - :height: 250pt - -#. Additionally, we get as console output the keypoints filtered: - - .. image:: images/Feature_FlannMatcher_Keypoints_Result.jpg - :align: center - :height: 250pt diff --git a/doc/tutorials/features2d/feature_homography/feature_homography.rst b/doc/tutorials/features2d/feature_homography/feature_homography.rst deleted file mode 100644 index f6acb70e4b..0000000000 --- a/doc/tutorials/features2d/feature_homography/feature_homography.rst +++ /dev/null @@ -1,149 +0,0 @@ -.. _feature_homography: - -Features2D + Homography to find a known object -********************************************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the function :find_homography:`findHomography<>` to find the transform between matched keypoints. - * Use the function :perspective_transform:`perspectiveTransform<>` to map the points. - - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. - -.. code-block:: cpp - - #include - #include - #include "opencv2/core.hpp" - #include "opencv2/features2d.hpp" - #include "opencv2/highgui.hpp" - #include "opencv2/calib3d.hpp" - #include "opencv2/xfeatures2d.hpp" - - using namespace cv; - using namespace cv::xfeatures2d; - - void readme(); - - /* @function main */ - int main( int argc, char** argv ) - { - if( argc != 3 ) - { readme(); return -1; } - - Mat img_object = imread( argv[1], IMREAD_GRAYSCALE ); - Mat img_scene = imread( argv[2], IMREAD_GRAYSCALE ); - - if( !img_object.data || !img_scene.data ) - { std::cout<< " --(!) Error reading images " << std::endl; return -1; } - - //-- Step 1: Detect the keypoints using SURF Detector - int minHessian = 400; - - SurfFeatureDetector detector( minHessian ); - - std::vector keypoints_object, keypoints_scene; - - detector.detect( img_object, keypoints_object ); - detector.detect( img_scene, keypoints_scene ); - - //-- Step 2: Calculate descriptors (feature vectors) - SurfDescriptorExtractor extractor; - - Mat descriptors_object, descriptors_scene; - - extractor.compute( img_object, keypoints_object, descriptors_object ); - extractor.compute( img_scene, keypoints_scene, descriptors_scene ); - - //-- Step 3: Matching descriptor vectors using FLANN matcher - FlannBasedMatcher matcher; - std::vector< DMatch > matches; - matcher.match( descriptors_object, descriptors_scene, matches ); - - double max_dist = 0; double min_dist = 100; - - //-- Quick calculation of max and min distances between keypoints - for( int i = 0; i < descriptors_object.rows; i++ ) - { double dist = matches[i].distance; - if( dist < min_dist ) min_dist = dist; - if( dist > max_dist ) max_dist = dist; - } - - printf("-- Max dist : %f \n", max_dist ); - printf("-- Min dist : %f \n", min_dist ); - - //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist ) - std::vector< DMatch > good_matches; - - for( int i = 0; i < descriptors_object.rows; i++ ) - { if( matches[i].distance < 3*min_dist ) - { good_matches.push_back( matches[i]); } - } - - Mat img_matches; - drawMatches( img_object, keypoints_object, img_scene, keypoints_scene, - good_matches, img_matches, Scalar::all(-1), Scalar::all(-1), - vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); - - //-- Localize the object - std::vector obj; - std::vector scene; - - for( int i = 0; i < good_matches.size(); i++ ) - { - //-- Get the keypoints from the good matches - obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt ); - scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt ); - } - - Mat H = findHomography( obj, scene, RANSAC ); - - //-- Get the corners from the image_1 ( the object to be "detected" ) - std::vector obj_corners(4); - obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img_object.cols, 0 ); - obj_corners[2] = cvPoint( img_object.cols, img_object.rows ); obj_corners[3] = cvPoint( 0, img_object.rows ); - std::vector scene_corners(4); - - perspectiveTransform( obj_corners, scene_corners, H); - - //-- Draw lines between the corners (the mapped object in the scene - image_2 ) - line( img_matches, scene_corners[0] + Point2f( img_object.cols, 0), scene_corners[1] + Point2f( img_object.cols, 0), Scalar(0, 255, 0), 4 ); - line( img_matches, scene_corners[1] + Point2f( img_object.cols, 0), scene_corners[2] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 ); - line( img_matches, scene_corners[2] + Point2f( img_object.cols, 0), scene_corners[3] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 ); - line( img_matches, scene_corners[3] + Point2f( img_object.cols, 0), scene_corners[0] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 ); - - //-- Show detected matches - imshow( "Good Matches & Object detection", img_matches ); - - waitKey(0); - return 0; - } - - /* @function readme */ - void readme() - { std::cout << " Usage: ./SURF_descriptor " << std::endl; } - -Explanation -============ - -Result -====== - - -#. And here is the result for the detected object (highlighted in green) - - .. image:: images/Feature_Homography_Result.jpg - :align: center - :height: 200pt diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/AKAZE_Match_Tutorial_Cover.png b/doc/tutorials/features2d/images/AKAZE_Match_Tutorial_Cover.png similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/AKAZE_Match_Tutorial_Cover.png rename to doc/tutorials/features2d/images/AKAZE_Match_Tutorial_Cover.png diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/AKAZE_Tracking_Tutorial_Cover.png b/doc/tutorials/features2d/images/AKAZE_Tracking_Tutorial_Cover.png similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/AKAZE_Tracking_Tutorial_Cover.png rename to doc/tutorials/features2d/images/AKAZE_Tracking_Tutorial_Cover.png diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/Feature_Description_Tutorial_Cover.jpg b/doc/tutorials/features2d/images/Feature_Description_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/Feature_Description_Tutorial_Cover.jpg rename to doc/tutorials/features2d/images/Feature_Description_Tutorial_Cover.jpg diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/Feature_Detection_Tutorial_Cover.jpg b/doc/tutorials/features2d/images/Feature_Detection_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/Feature_Detection_Tutorial_Cover.jpg rename to doc/tutorials/features2d/images/Feature_Detection_Tutorial_Cover.jpg diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/Feature_Flann_Matcher_Tutorial_Cover.jpg b/doc/tutorials/features2d/images/Feature_Flann_Matcher_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/Feature_Flann_Matcher_Tutorial_Cover.jpg rename to doc/tutorials/features2d/images/Feature_Flann_Matcher_Tutorial_Cover.jpg diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/Feature_Homography_Tutorial_Cover.jpg b/doc/tutorials/features2d/images/Feature_Homography_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/Feature_Homography_Tutorial_Cover.jpg rename to doc/tutorials/features2d/images/Feature_Homography_Tutorial_Cover.jpg diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/detection_of_planar_objects.png b/doc/tutorials/features2d/images/detection_of_planar_objects.png similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/detection_of_planar_objects.png rename to doc/tutorials/features2d/images/detection_of_planar_objects.png diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Corner_Subpixeles_Cover.jpg b/doc/tutorials/features2d/images/trackingmotion/Corner_Subpixeles_Cover.jpg similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Corner_Subpixeles_Cover.jpg rename to doc/tutorials/features2d/images/trackingmotion/Corner_Subpixeles_Cover.jpg diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Generic_Corner_Detector_Cover.jpg b/doc/tutorials/features2d/images/trackingmotion/Generic_Corner_Detector_Cover.jpg similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Generic_Corner_Detector_Cover.jpg rename to doc/tutorials/features2d/images/trackingmotion/Generic_Corner_Detector_Cover.jpg diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Harris_Detector_Cover.jpg b/doc/tutorials/features2d/images/trackingmotion/Harris_Detector_Cover.jpg similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Harris_Detector_Cover.jpg rename to doc/tutorials/features2d/images/trackingmotion/Harris_Detector_Cover.jpg diff --git a/doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Shi_Tomasi_Detector_Cover.jpg b/doc/tutorials/features2d/images/trackingmotion/Shi_Tomasi_Detector_Cover.jpg similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/images/trackingmotion/Shi_Tomasi_Detector_Cover.jpg rename to doc/tutorials/features2d/images/trackingmotion/Shi_Tomasi_Detector_Cover.jpg diff --git a/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.markdown b/doc/tutorials/features2d/table_of_content_features2d.markdown similarity index 100% rename from doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.markdown rename to doc/tutorials/features2d/table_of_content_features2d.markdown diff --git a/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.rst b/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.rst deleted file mode 100644 index 50b684cf56..0000000000 --- a/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.rst +++ /dev/null @@ -1,239 +0,0 @@ -.. _Table-Of-Content-Feature2D: - -*feature2d* module. 2D Features framework ------------------------------------------------------------ - -Learn about how to use the feature points detectors, descriptors and matching framework found inside OpenCV. - -.. include:: ../../definitions/tocDefinitions.rst - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |Harris| **Title:** :ref:`harris_detector` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Why is it a good idea to track corners? We learn to use the Harris method to detect corners - - ===================== ============================================== - - .. |Harris| image:: images/trackingmotion/Harris_Detector_Cover.jpg - :height: 90pt - :width: 90pt - - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |ShiTomasi| **Title:** :ref:`good_features_to_track` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we use an improved method to detect corners more accuratelyI - - ===================== ============================================== - - .. |ShiTomasi| image:: images/trackingmotion/Shi_Tomasi_Detector_Cover.jpg - :height: 90pt - :width: 90pt - - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |GenericCorner| **Title:** :ref:`generic_corner_detector` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Here you will learn how to use OpenCV functions to make your personalized corner detector! - - ===================== ============================================== - - .. |GenericCorner| image:: images/trackingmotion/Generic_Corner_Detector_Cover.jpg - :height: 90pt - :width: 90pt - - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |Subpixel| **Title:** :ref:`corner_subpixeles` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Is pixel resolution enough? Here we learn a simple method to improve our accuracy. - - ===================== ============================================== - - .. |Subpixel| image:: images/trackingmotion/Corner_Subpixeles_Cover.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |FeatureDetect| **Title:** :ref:`feature_detection` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - In this tutorial, you will use *features2d* to detect interest points. - - ===================== ============================================== - - .. |FeatureDetect| image:: images/Feature_Detection_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |FeatureDescript| **Title:** :ref:`feature_description` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - In this tutorial, you will use *features2d* to calculate feature vectors. - - ===================== ============================================== - - .. |FeatureDescript| image:: images/Feature_Description_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |FeatureFlann| **Title:** :ref:`feature_flann_matcher` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - In this tutorial, you will use the FLANN library to make a fast matching. - - ===================== ============================================== - - .. |FeatureFlann| image:: images/Feature_Flann_Matcher_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |FeatureHomo| **Title:** :ref:`feature_homography` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - In this tutorial, you will use *features2d* and *calib3d* to detect an object in a scene. - - ===================== ============================================== - - .. |FeatureHomo| image:: images/Feature_Homography_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |DetectPlanar| **Title:** :ref:`detectionOfPlanarObjects` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_VictorE| - - You will use *features2d* and *calib3d* modules for detecting known planar objects in scenes. - - ===================== ============================================== - - .. |DetectPlanar| image:: images/detection_of_planar_objects.png - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |AkazeMatch| **Title:** :ref:`akazeMatching` - - *Compatibility:* > OpenCV 3.0 - - *Author:* Fedor Morozov - - Using *AKAZE* local features to find correspondence between two images. - - ===================== ============================================== - - .. |AkazeMatch| image:: images/AKAZE_Match_Tutorial_Cover.png - :height: 90pt - :width: 90pt - - ===================== ============================================== - |AkazeTracking| **Title:** :ref:`akazeTracking` - - *Compatibility:* > OpenCV 3.0 - - *Author:* Fedor Morozov - - Using *AKAZE* and *ORB* for planar object tracking. - - ===================== ============================================== - - .. |AkazeTracking| image:: images/AKAZE_Tracking_Tutorial_Cover.png - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. toctree:: - :hidden: - - ../feature_description/feature_description - ../trackingmotion/harris_detector/harris_detector - ../feature_flann_matcher/feature_flann_matcher - ../feature_homography/feature_homography - ../trackingmotion/good_features_to_track/good_features_to_track.rst - ../trackingmotion/generic_corner_detector/generic_corner_detector - ../trackingmotion/corner_subpixeles/corner_subpixeles - ../feature_detection/feature_detection - ../feature_flann_matcher/feature_flann_matcher - ../feature_homography/feature_homography - ../detection_of_planar_objects/detection_of_planar_objects - ../akaze_matching/akaze_matching - ../akaze_tracking/akaze_tracking diff --git a/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.rst b/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.rst deleted file mode 100644 index 4f816ccbb8..0000000000 --- a/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.rst +++ /dev/null @@ -1,137 +0,0 @@ -.. _corner_subpixeles: - -Detecting corners location in subpixeles -**************************************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :corner_sub_pix:`cornerSubPix <>` to find more exact corner positions (more exact than integer pixels). - - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - #include - - using namespace cv; - using namespace std; - - /// Global variables - Mat src, src_gray; - - int maxCorners = 10; - int maxTrackbar = 25; - - RNG rng(12345); - char* source_window = "Image"; - - /// Function header - void goodFeaturesToTrack_Demo( int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load source image and convert it to gray - src = imread( argv[1], 1 ); - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - - /// Create Window - namedWindow( source_window, WINDOW_AUTOSIZE ); - - /// Create Trackbar to set the number of corners - createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo); - - imshow( source_window, src ); - - goodFeaturesToTrack_Demo( 0, 0 ); - - waitKey(0); - return(0); - } - - /* - * @function goodFeaturesToTrack_Demo.cpp - * @brief Apply Shi-Tomasi corner detector - */ - void goodFeaturesToTrack_Demo( int, void* ) - { - if( maxCorners < 1 ) { maxCorners = 1; } - - /// Parameters for Shi-Tomasi algorithm - vector corners; - double qualityLevel = 0.01; - double minDistance = 10; - int blockSize = 3; - bool useHarrisDetector = false; - double k = 0.04; - - /// Copy the source image - Mat copy; - copy = src.clone(); - - /// Apply corner detection - goodFeaturesToTrack( src_gray, - corners, - maxCorners, - qualityLevel, - minDistance, - Mat(), - blockSize, - useHarrisDetector, - k ); - - - /// Draw corners detected - cout<<"** Number of corners detected: "<` to find the eigenvalues and eigenvectors to determine if a pixel is a corner. - * Use the OpenCV function :corner_min_eigenval:`cornerMinEigenVal <>` to find the minimum eigenvalues for corner detection. - * To implement our own version of the Harris detector as well as the Shi-Tomasi detector, by using the two functions above. - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. literalinclude:: ../../../../../samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp - :language: cpp - -Explanation -============ - -Result -====== - -.. image:: images/My_Harris_corner_detector_Result.jpg - :align: center - - -.. image:: images/My_Shi_Tomasi_corner_detector_Result.jpg - :align: center diff --git a/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.rst b/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.rst deleted file mode 100644 index 656f5a0a6a..0000000000 --- a/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.rst +++ /dev/null @@ -1,120 +0,0 @@ -.. _good_features_to_track: - -Shi-Tomasi corner detector -************************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the function :good_features_to_track:`goodFeaturesToTrack <>` to detect corners using the Shi-Tomasi method. - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - #include - - using namespace cv; - using namespace std; - - /// Global variables - Mat src, src_gray; - - int maxCorners = 23; - int maxTrackbar = 100; - - RNG rng(12345); - char* source_window = "Image"; - - /// Function header - void goodFeaturesToTrack_Demo( int, void* ); - - /* - * @function main - */ - int main( int argc, char** argv ) - { - /// Load source image and convert it to gray - src = imread( argv[1], 1 ); - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - - /// Create Window - namedWindow( source_window, WINDOW_AUTOSIZE ); - - /// Create Trackbar to set the number of corners - createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo ); - - imshow( source_window, src ); - - goodFeaturesToTrack_Demo( 0, 0 ); - - waitKey(0); - return(0); - } - - /* - * @function goodFeaturesToTrack_Demo.cpp - * @brief Apply Shi-Tomasi corner detector - */ - void goodFeaturesToTrack_Demo( int, void* ) - { - if( maxCorners < 1 ) { maxCorners = 1; } - - /// Parameters for Shi-Tomasi algorithm - vector corners; - double qualityLevel = 0.01; - double minDistance = 10; - int blockSize = 3; - bool useHarrisDetector = false; - double k = 0.04; - - /// Copy the source image - Mat copy; - copy = src.clone(); - - /// Apply corner detection - goodFeaturesToTrack( src_gray, - corners, - maxCorners, - qualityLevel, - minDistance, - Mat(), - blockSize, - useHarrisDetector, - k ); - - - /// Draw corners detected - cout<<"** Number of corners detected: "<` to detect corners using the Harris-Stephens method. - -Theory -====== - -What is a feature? -------------------- - -.. container:: enumeratevisibleitemswithsquare - - * In computer vision, usually we need to find matching points between different frames of an environment. Why? If we know how two images relate to each other, we can use *both* images to extract information of them. - - * When we say **matching points** we are referring, in a general sense, to *characteristics* in the scene that we can recognize easily. We call these characteristics **features**. - - * **So, what characteristics should a feature have?** - - * It must be *uniquely recognizable* - - -Types of Image Features ------------------------- - -To mention a few: - -.. container:: enumeratevisibleitemswithsquare - - * Edges - * **Corners** (also known as interest points) - * Blobs (also known as regions of interest ) - -In this tutorial we will study the *corner* features, specifically. - -Why is a corner so special? ----------------------------- - -.. container:: enumeratevisibleitemswithsquare - - * Because, since it is the intersection of two edges, it represents a point in which the directions of these two edges *change*. Hence, the gradient of the image (in both directions) have a high variation, which can be used to detect it. - - -How does it work? ------------------ - -.. container:: enumeratevisibleitemswithsquare - - * Let's look for corners. Since corners represents a variation in the gradient in the image, we will look for this "variation". - - * Consider a grayscale image :math:`I`. We are going to sweep a window :math:`w(x,y)` (with displacements :math:`u` in the x direction and :math:`v` in the right direction) :math:`I` and will calculate the variation of intensity. - - .. math:: - - E(u,v) = \sum _{x,y} w(x,y)[ I(x+u,y+v) - I(x,y)]^{2} - - where: - - * :math:`w(x,y)` is the window at position :math:`(x,y)` - * :math:`I(x,y)` is the intensity at :math:`(x,y)` - * :math:`I(x+u,y+v)` is the intensity at the moved window :math:`(x+u,y+v)` - - * Since we are looking for windows with corners, we are looking for windows with a large variation in intensity. Hence, we have to maximize the equation above, specifically the term: - - .. math:: - - \sum _{x,y}[ I(x+u,y+v) - I(x,y)]^{2} - - - * Using *Taylor expansion*: - - .. math:: - - E(u,v) \approx \sum _{x,y}[ I(x,y) + u I_{x} + vI_{y} - I(x,y)]^{2} - - - * Expanding the equation and cancelling properly: - - .. math:: - - E(u,v) \approx \sum _{x,y} u^{2}I_{x}^{2} + 2uvI_{x}I_{y} + v^{2}I_{y}^{2} - - * Which can be expressed in a matrix form as: - - .. math:: - - E(u,v) \approx \begin{bmatrix} - u & v - \end{bmatrix} - \left ( - \displaystyle \sum_{x,y} - w(x,y) - \begin{bmatrix} - I_x^{2} & I_{x}I_{y} \\ - I_xI_{y} & I_{y}^{2} - \end{bmatrix} - \right ) - \begin{bmatrix} - u \\ - v - \end{bmatrix} - - * Let's denote: - - .. math:: - - M = \displaystyle \sum_{x,y} - w(x,y) - \begin{bmatrix} - I_x^{2} & I_{x}I_{y} \\ - I_xI_{y} & I_{y}^{2} - \end{bmatrix} - - * So, our equation now is: - - .. math:: - - E(u,v) \approx \begin{bmatrix} - u & v - \end{bmatrix} - M - \begin{bmatrix} - u \\ - v - \end{bmatrix} - - - * A score is calculated for each window, to determine if it can possibly contain a corner: - - .. math:: - - R = det(M) - k(trace(M))^{2} - - where: - - * det(M) = :math:`\lambda_{1}\lambda_{2}` - * trace(M) = :math:`\lambda_{1}+\lambda_{2}` - - a window with a score :math:`R` greater than a certain value is considered a "corner" - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - #include - - using namespace cv; - using namespace std; - - /// Global variables - Mat src, src_gray; - int thresh = 200; - int max_thresh = 255; - - char* source_window = "Source image"; - char* corners_window = "Corners detected"; - - /// Function header - void cornerHarris_demo( int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load source image and convert it to gray - src = imread( argv[1], 1 ); - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - - /// Create a window and a trackbar - namedWindow( source_window, WINDOW_AUTOSIZE ); - createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo ); - imshow( source_window, src ); - - cornerHarris_demo( 0, 0 ); - - waitKey(0); - return(0); - } - - /* @function cornerHarris_demo */ - void cornerHarris_demo( int, void* ) - { - - Mat dst, dst_norm, dst_norm_scaled; - dst = Mat::zeros( src.size(), CV_32FC1 ); - - /// Detector parameters - int blockSize = 2; - int apertureSize = 3; - double k = 0.04; - - /// Detecting corners - cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT ); - - /// Normalizing - normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() ); - convertScaleAbs( dst_norm, dst_norm_scaled ); - - /// Drawing a circle around corners - for( int j = 0; j < dst_norm.rows ; j++ ) - { for( int i = 0; i < dst_norm.cols; i++ ) - { - if( (int) dst_norm.at(j,i) > thresh ) - { - circle( dst_norm_scaled, Point( i, j ), 5, Scalar(0), 2, 8, 0 ); - } - } - } - /// Showing the result - namedWindow( corners_window, WINDOW_AUTOSIZE ); - imshow( corners_window, dst_norm_scaled ); - } - - -Explanation -============ - -Result -====== - -The original image: - -.. image:: images/Harris_Detector_Original_Image.jpg - :align: center - -The detected corners are surrounded by a small black circle - -.. image:: images/Harris_Detector_Result.jpg - :align: center diff --git a/doc/tutorials/general/table_of_content_general/table_of_content_general.rst b/doc/tutorials/general/table_of_content_general/table_of_content_general.rst deleted file mode 100644 index 6e127a98f6..0000000000 --- a/doc/tutorials/general/table_of_content_general/table_of_content_general.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _Table-Of-Content-General: - -General tutorials ------------------------------------------------------------ - -These tutorials are the bottom of the iceberg as they link together multiple of the modules presented above in order to solve complex problems. - -.. include:: ../../definitions/noContent.rst - -.. raw:: latex - - \pagebreak diff --git a/doc/tutorials/gpu/gpu-basics-similarity/gpu-basics-similarity.rst b/doc/tutorials/gpu/gpu-basics-similarity/gpu-basics-similarity.rst deleted file mode 100644 index 2e8fe9559b..0000000000 --- a/doc/tutorials/gpu/gpu-basics-similarity/gpu-basics-similarity.rst +++ /dev/null @@ -1,234 +0,0 @@ -.. _gpuBasicsSimilarity: - -Similarity check (PNSR and SSIM) on the GPU -******************************************* - -Goal -==== - -In the :ref:`videoInputPSNRMSSIM` tutorial I already presented the PSNR and SSIM methods for -checking the similarity between the two images. And as you could see there performing these takes -quite some time, especially in the case of the SSIM. However, if the performance numbers of an -OpenCV implementation for the CPU do not satisfy you and you happen to have an NVidia CUDA GPU -device in your system all is not lost. You may try to port or write your algorithm for the video -card. - -This tutorial will give a good grasp on how to approach coding by using the GPU module of OpenCV. As -a prerequisite you should already know how to handle the core, highgui and imgproc modules. So, our -goals are: - -.. container:: enumeratevisibleitemswithsquare - - + What's different compared to the CPU? - + Create the GPU code for the PSNR and SSIM - + Optimize the code for maximal performance - -The source code -=============== - -You may also find the source code and these video file in the -:file:`samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity` folder of the -OpenCV source library or :download:`download it from here -<../../../../samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp>`. The -full source code is quite long (due to the controlling of the application via the command line -arguments and performance measurement). Therefore, to avoid cluttering up these sections with those -you'll find here only the functions itself. - -The PSNR returns a float number, that if the two inputs are similar between 30 and 50 (higher is -better). - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 165-210, 18-23, 210-235 - -The SSIM returns the MSSIM of the images. This is too a float number between zero and one (higher is -better), however we have one for each channel. Therefore, we return a *Scalar* OpenCV data -structure: - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 235-355, 26-42, 357- - -How to do it? - The GPU -======================= - -Now as you can see we have three types of functions for each operation. One for the CPU and two for -the GPU. The reason I made two for the GPU is too illustrate that often simple porting your CPU to -GPU will actually make it slower. If you want some performance gain you will need to remember a few -rules, whose I'm going to detail later on. - -The development of the GPU module was made so that it resembles as much as possible its CPU -counterpart. This is to make porting easy. The first thing you need to do before writing any code is -to link the GPU module to your project, and include the header file for the module. All the -functions and data structures of the GPU are in a *gpu* sub namespace of the *cv* namespace. You may -add this to the default one via the *use namespace* keyword, or mark it everywhere explicitly via -the cv:: to avoid confusion. I'll do the later. - -.. code-block:: cpp - - #include // GPU structures and methods - -GPU stands for **g**\ raphics **p**\ rocessing **u**\ nit. It was originally build to render -graphical scenes. These scenes somehow build on a lot of data. Nevertheless, these aren't all -dependent one from another in a sequential way and as it is possible a parallel processing of them. -Due to this a GPU will contain multiple smaller processing units. These aren't the state of the art -processors and on a one on one test with a CPU it will fall behind. However, its strength lies in -its numbers. In the last years there has been an increasing trend to harvest these massive parallel -powers of the GPU in non-graphical scene rendering too. This gave birth to the general-purpose -computation on graphics processing units (GPGPU). - -The GPU has its own memory. When you read data from the hard drive with OpenCV into a *Mat* object -that takes place in your systems memory. The CPU works somehow directly on this (via its cache), -however the GPU cannot. He has too transferred the information he will use for calculations from the -system memory to its own. This is done via an upload process and takes time. In the end the result -will have to be downloaded back to your system memory for your CPU to see it and use it. Porting -small functions to GPU is not recommended as the upload/download time will be larger than the amount -you gain by a parallel execution. - -Mat objects are stored only in the system memory (or the CPU cache). For getting an OpenCV matrix -to the GPU you'll need to use its GPU counterpart :gpudatastructure:`GpuMat `. It works -similar to the Mat with a 2D only limitation and no reference returning for its functions (cannot -mix GPU references with CPU ones). To upload a Mat object to the GPU you need to call the upload -function after creating an instance of the class. To download you may use simple assignment to a -Mat object or use the download function. - -.. code-block:: cpp - - Mat I1; // Main memory item - read image into with imread for example - gpu::GpuMat gI; // GPU matrix - for now empty - gI1.upload(I1); // Upload a data from the system memory to the GPU memory - - I1 = gI1; // Download, gI1.download(I1) will work too - -Once you have your data up in the GPU memory you may call GPU enabled functions of OpenCV. Most of -the functions keep the same name just as on the CPU, with the difference that they only accept -*GpuMat* inputs. A full list of these you will find in the documentation: `online here -`_ or the OpenCV reference manual that comes with -the source code. - -Another thing to keep in mind is that not for all channel numbers you can make efficient algorithms -on the GPU. Generally, I found that the input images for the GPU images need to be either one or -four channel ones and one of the char or float type for the item sizes. No double support on the -GPU, sorry. Passing other types of objects for some functions will result in an exception thrown, -and an error message on the error output. The documentation details in most of the places the types -accepted for the inputs. If you have three channel images as an input you can do two things: either -adds a new channel (and use char elements) or split up the image and call the function for each -image. The first one isn't really recommended as you waste memory. - -For some functions, where the position of the elements (neighbor items) doesn't matter quick -solution is to just reshape it into a single channel image. This is the case for the PSNR -implementation where for the *absdiff* method the value of the neighbors is not important. However, -for the *GaussianBlur* this isn't an option and such need to use the split method for the SSIM. With -this knowledge you can already make a GPU viable code (like mine GPU one) and run it. You'll be -surprised to see that it might turn out slower than your CPU implementation. - -Optimization -============ - -The reason for this is that you're throwing out on the window the price for memory allocation and -data transfer. And on the GPU this is damn high. Another possibility for optimization is to -introduce asynchronous OpenCV GPU calls too with the help of the -:gpudatastructure:`gpu::Stream`. - -1. Memory allocation on the GPU is considerable. Therefore, if it’s possible allocate new memory as - few times as possible. If you create a function what you intend to call multiple times it is a - good idea to allocate any local parameters for the function only once, during the first call. - To do this you create a data structure containing all the local variables you will use. For - instance in case of the PSNR these are: - - .. code-block:: cpp - - struct BufferPSNR // Optimized GPU versions - { // Data allocations are very expensive on GPU. Use a buffer to solve: allocate once reuse later. - gpu::GpuMat gI1, gI2, gs, t1,t2; - - gpu::GpuMat buf; - }; - - Then create an instance of this in the main program: - - .. code-block:: cpp - - BufferPSNR bufferPSNR; - - And finally pass this to the function each time you call it: - - .. code-block:: cpp - - double getPSNR_GPU_optimized(const Mat& I1, const Mat& I2, BufferPSNR& b) - - Now you access these local parameters as: *b.gI1*, *b.buf* and so on. The GpuMat will only - reallocate itself on a new call if the new matrix size is different from the previous one. - -#. Avoid unnecessary function data transfers. Any small data transfer will be significant one once - you go to the GPU. Therefore, if possible make all calculations in-place (in other words do not - create new memory objects - for reasons explained at the previous point). For example, although - expressing arithmetical operations may be easier to express in one line formulas, it will be - slower. In case of the SSIM at one point I need to calculate: - - .. code-block:: cpp - - b.t1 = 2 * b.mu1_mu2 + C1; - - Although the upper call will succeed observe that there is a hidden data transfer present. Before - it makes the addition it needs to store somewhere the multiplication. Therefore, it will create a - local matrix in the background, add to that the *C1* value and finally assign that to *t1*. To - avoid this we use the gpu functions, instead of the arithmetic operators: - - .. code-block:: cpp - - gpu::multiply(b.mu1_mu2, 2, b.t1); //b.t1 = 2 * b.mu1_mu2 + C1; - gpu::add(b.t1, C1, b.t1); - -#. Use asynchronous calls (the :gpudatastructure:`gpu::Stream `). By default whenever - you call a gpu function it will wait for the call to finish and return with the result - afterwards. However, it is possible to make asynchronous calls, meaning it will call for the - operation execution, make the costly data allocations for the algorithm and return back right - away. Now you can call another function if you wish to do so. For the MSSIM this is a small - optimization point. In our default implementation we split up the image into channels and call - then for each channel the gpu functions. A small degree of parallelization is possible with the - stream. By using a stream we can make the data allocation, upload operations while the GPU is - already executing a given method. For example we need to upload two images. We queue these one - after another and call already the function that processes it. The functions will wait for the - upload to finish, however while that happens makes the output buffer allocations for the function - to be executed next. - - .. code-block:: cpp - - gpu::Stream stream; - - stream.enqueueConvert(b.gI1, b.t1, CV_32F); // Upload - - gpu::split(b.t1, b.vI1, stream); // Methods (pass the stream as final parameter). - gpu::multiply(b.vI1[i], b.vI1[i], b.I1_2, stream); // I1^2 - -Result and conclusion -===================== - -On an Intel P8700 laptop CPU paired with a low end NVidia GT220M here are the performance numbers: - -.. code-block:: cpp - - Time of PSNR CPU (averaged for 10 runs): 41.4122 milliseconds. With result of: 19.2506 - Time of PSNR GPU (averaged for 10 runs): 158.977 milliseconds. With result of: 19.2506 - Initial call GPU optimized: 31.3418 milliseconds. With result of: 19.2506 - Time of PSNR GPU OPTIMIZED ( / 10 runs): 24.8171 milliseconds. With result of: 19.2506 - - Time of MSSIM CPU (averaged for 10 runs): 484.343 milliseconds. With result of B0.890964 G0.903845 R0.936934 - Time of MSSIM GPU (averaged for 10 runs): 745.105 milliseconds. With result of B0.89922 G0.909051 R0.968223 - Time of MSSIM GPU Initial Call 357.746 milliseconds. With result of B0.890964 G0.903845 R0.936934 - Time of MSSIM GPU OPTIMIZED ( / 10 runs): 203.091 milliseconds. With result of B0.890964 G0.903845 R0.936934 - -In both cases we managed a performance increase of almost 100% compared to the CPU implementation. -It may be just the improvement needed for your application to work. You may observe a runtime -instance of this on the `YouTube here `_. - -.. raw:: html - -
- -
diff --git a/doc/tutorials/gpu/gpu-basics-similarity/gpu_basics_similarity.markdown b/doc/tutorials/gpu/gpu-basics-similarity/gpu_basics_similarity.markdown index e24fe03598..cf8aba954d 100644 --- a/doc/tutorials/gpu/gpu-basics-similarity/gpu_basics_similarity.markdown +++ b/doc/tutorials/gpu/gpu-basics-similarity/gpu_basics_similarity.markdown @@ -24,7 +24,7 @@ The source code You may also find the source code and these video file in the `samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity` folder of the OpenCV -source library or download it from [here](samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp). +source library or download it from [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp). The full source code is quite long (due to the controlling of the application via the command line arguments and performance measurement). Therefore, to avoid cluttering up these sections with those you'll find here only the functions itself. @@ -32,37 +32,19 @@ you'll find here only the functions itself. The PSNR returns a float number, that if the two inputs are similar between 30 and 50 (higher is better). -@dontinclude samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp - -@skip struct BufferPSNR -@until }; - -@skip double getPSNR( -@until return psnr; -@until } -@until } - -@skip double getPSNR_CUDA( -@until return psnr; -@until } -@until } +@snippet samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp getpsnr +@snippet samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp getpsnrcuda +@snippet samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp psnr +@snippet samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp getpsnropt The SSIM returns the MSSIM of the images. This is too a float number between zero and one (higher is better), however we have one for each channel. Therefore, we return a *Scalar* OpenCV data structure: -@dontinclude samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp - -@skip struct BufferMSSIM -@until }; - -@skip Scalar getMSSIM( -@until return mssim; -@until } - -@skip Scalar getMSSIM_CUDA_optimized( -@until return mssim; -@until } +@snippet samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp getssim +@snippet samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp getssimcuda +@snippet samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp ssim +@snippet samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp getssimopt How to do it? - The GPU ----------------------- diff --git a/doc/tutorials/gpu/table_of_content_gpu/images/gpu-basics-similarity.png b/doc/tutorials/gpu/images/gpu-basics-similarity.png similarity index 100% rename from doc/tutorials/gpu/table_of_content_gpu/images/gpu-basics-similarity.png rename to doc/tutorials/gpu/images/gpu-basics-similarity.png diff --git a/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.markdown b/doc/tutorials/gpu/table_of_content_gpu.markdown similarity index 100% rename from doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.markdown rename to doc/tutorials/gpu/table_of_content_gpu.markdown diff --git a/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.rst b/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.rst deleted file mode 100644 index 91b25833bc..0000000000 --- a/doc/tutorials/gpu/table_of_content_gpu/table_of_content_gpu.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _Table-Of-Content-GPU: - -*gpu* module. GPU-Accelerated Computer Vision ---------------------------------------------- - -Squeeze out every little computation power from your system by using the power of your video card to run the OpenCV algorithms. - -.. include:: ../../definitions/tocDefinitions.rst - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |hVideoWrite| *Title:* :ref:`gpuBasicsSimilarity` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - This will give a good grasp on how to approach coding on the GPU module, once you already know how to handle the other modules. As a test case it will port the similarity methods from the tutorial :ref:`videoInputPSNRMSSIM` to the GPU. - - =============== ====================================================== - - .. |hVideoWrite| image:: images/gpu-basics-similarity.png - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. toctree:: - :hidden: - - ../gpu-basics-similarity/gpu-basics-similarity diff --git a/doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.jpg b/doc/tutorials/highgui/images/Adding_Trackbars_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/highgui/table_of_content_highgui/images/Adding_Trackbars_Tutorial_Cover.jpg rename to doc/tutorials/highgui/images/Adding_Trackbars_Tutorial_Cover.jpg diff --git a/doc/tutorials/highgui/table_of_content_highgui/images/gdal-io.jpg b/doc/tutorials/highgui/images/gdal-io.jpg similarity index 100% rename from doc/tutorials/highgui/table_of_content_highgui/images/gdal-io.jpg rename to doc/tutorials/highgui/images/gdal-io.jpg diff --git a/doc/tutorials/highgui/table_of_content_highgui/images/video-input-psnr-ssim.png b/doc/tutorials/highgui/images/video-input-psnr-ssim.png similarity index 100% rename from doc/tutorials/highgui/table_of_content_highgui/images/video-input-psnr-ssim.png rename to doc/tutorials/highgui/images/video-input-psnr-ssim.png diff --git a/doc/tutorials/highgui/table_of_content_highgui/images/video-write.png b/doc/tutorials/highgui/images/video-write.png similarity index 100% rename from doc/tutorials/highgui/table_of_content_highgui/images/video-write.png rename to doc/tutorials/highgui/images/video-write.png diff --git a/doc/tutorials/highgui/raster-gdal/raster_io_gdal.rst b/doc/tutorials/highgui/raster-gdal/raster_io_gdal.rst deleted file mode 100644 index 91932a35bb..0000000000 --- a/doc/tutorials/highgui/raster-gdal/raster_io_gdal.rst +++ /dev/null @@ -1,113 +0,0 @@ -.. _Raster_IO_GDAL: - - -Reading Geospatial Raster files with GDAL -***************************************** - -Geospatial raster data is a heavily used product in Geographic Information -Systems and Photogrammetry. Raster data typically can represent imagery -and Digital Elevation Models (DEM). The standard library for loading -GIS imagery is the Geographic Data Abstraction Library (GDAL). In this example, we -will show techniques for loading GIS raster formats using native OpenCV functions. -In addition, we will show some an example of how OpenCV can use this data for -novel and interesting purposes. - -Goals -===== - -The primary objectives for this tutorial: - -.. container:: enumeratevisibleitemswithsquare - - + How to use OpenCV imread to load satellite imagery. - + How to use OpenCV imread to load SRTM Digital Elevation Models - + Given the corner coordinates of both the image and DEM, correllate the elevation data to the image to find elevations for each pixel. - + Show a basic, easy-to-implement example of a terrain heat map. - + Show a basic use of DEM data coupled with ortho-rectified imagery. - -To implement these goals, the following code takes a Digital Elevation Model as well as a GeoTiff image of San Francisco as input. -The image and DEM data is processed and generates a terrain heat map of the image as well as labels areas of the city which would -be affected should the water level of the bay rise 10, 50, and 100 meters. - -Code -==== - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/HighGUI/GDAL_IO/gdal-image.cpp - :language: cpp - :linenos: - :tab-width: 4 - - -How to Read Raster Data using GDAL -====================================== - -This demonstration uses the default OpenCV :ocv:func:`imread` function. The primary difference is that in order to force GDAL to load the -image, you must use the appropriate flag. - -.. code-block:: cpp - - cv::Mat image = cv::imread( argv[1], cv::IMREAD_LOAD_GDAL ); - -When loading digital elevation models, the actual numeric value of each pixel is essential -and cannot be scaled or truncated. For example, with image data a pixel represented as a double with a value of 1 has -an equal appearance to a pixel which is represented as an unsigned character with a value of 255. -With terrain data, the pixel value represents the elevation in meters. In order to ensure that OpenCV preserves the native value, -use the GDAL flag in imread with the ANYDEPTH flag. - -.. code-block:: cpp - - cv::Mat dem = cv::imread( argv[2], cv::IMREAD_LOAD_GDAL | cv::IMREAD_ANYDEPTH ); - - -If you know beforehand the type of DEM model you are loading, then it may be a safe bet to test the ``Mat::type()`` or ``Mat::depth()`` -using an assert or other mechanism. NASA or DOD specification documents can provide the input types for various -elevation models. The major types, SRTM and DTED, are both signed shorts. - -Notes -===== - -Lat/Lon (Geodetic) Coordinates should normally be avoided ---------------------------------------------------------- - -The Geodetic Coordinate System is a spherical coordinate system, meaning that using them with Cartesian mathematics is technically incorrect. This -demo uses them to increase the readability and is accurate enough to make the point. A better coordinate system would be Universal Transverse Mercator. - -Finding the corner coordinates ------------------------------- - -One easy method to find the corner coordinates of an image is to use the command-line tool ``gdalinfo``. For imagery which is ortho-rectified and contains -the projection information, you can use the `USGS EarthExplorer `_. - -.. code-block:: bash - - $> gdalinfo N37W123.hgt - - Driver: SRTMHGT/SRTMHGT File Format - Files: N37W123.hgt - Size is 3601, 3601 - Coordinate System is: - GEOGCS["WGS 84", - DATUM["WGS_1984", - - ... more output ... - - Corner Coordinates: - Upper Left (-123.0001389, 38.0001389) (123d 0' 0.50"W, 38d 0' 0.50"N) - Lower Left (-123.0001389, 36.9998611) (123d 0' 0.50"W, 36d59'59.50"N) - Upper Right (-121.9998611, 38.0001389) (121d59'59.50"W, 38d 0' 0.50"N) - Lower Right (-121.9998611, 36.9998611) (121d59'59.50"W, 36d59'59.50"N) - Center (-122.5000000, 37.5000000) (122d30' 0.00"W, 37d30' 0.00"N) - - ... more output ... - - -Results -======= - -Below is the output of the program. Use the first image as the input. For the DEM model, download the SRTM file located at the USGS here. `http://dds.cr.usgs.gov/srtm/version2_1/SRTM1/Region_04/N37W123.hgt.zip `_ - -.. image:: images/gdal_output.jpg - -.. image:: images/gdal_heat-map.jpg - -.. image:: images/gdal_flood-zone.jpg diff --git a/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.markdown b/doc/tutorials/highgui/table_of_content_highgui.markdown similarity index 100% rename from doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.markdown rename to doc/tutorials/highgui/table_of_content_highgui.markdown diff --git a/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.rst b/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.rst deleted file mode 100644 index 8b6a9c72e1..0000000000 --- a/doc/tutorials/highgui/table_of_content_highgui/table_of_content_highgui.rst +++ /dev/null @@ -1,98 +0,0 @@ -.. _Table-Of-Content-HighGui: - -*highgui* module. High Level GUI and Media ------------------------------------------- - -This section contains valuable tutorials about how to read/save your image/video files and how to use the built-in graphical user interface of the library. - -.. include:: ../../definitions/tocDefinitions.rst - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |Beginners_5| *Title:* :ref:`Adding_Trackbars` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to add a Trackbar to our applications - - =============== ====================================================== - - .. |Beginners_5| image:: images/Adding_Trackbars_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |hVideoInput| *Title:* :ref:`videoInputPSNRMSSIM` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - You will learn how to read video streams, and how to calculate similarity values such as PSNR or SSIM. - - =============== ====================================================== - - .. |hVideoInput| image:: images/video-input-psnr-ssim.png - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |hVideoWrite| *Title:* :ref:`videoWriteHighGui` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - Whenever you work with video feeds you may eventually want to save your image processing result in a form of a new video file. Here's how to do it. - - =============== ====================================================== - - .. |hVideoWrite| image:: images/video-write.png - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |hGDAL_IO| *Title:* :ref:`Raster_IO_GDAL` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_MarvinS| - - Read common GIS Raster and DEM files to display and manipulate geographic data. - - =============== ====================================================== - - .. |hGDAL_IO| image:: images/gdal-io.jpg - :height: 90pt - :width: 90pt - - - -.. raw:: latex - - \pagebreak - -.. toctree:: - :hidden: - - ../trackbar/trackbar - ../video-input-psnr-ssim/video-input-psnr-ssim - ../video-write/video-write - ../raster-gdal/raster_io_gdal diff --git a/doc/tutorials/highgui/trackbar/trackbar.rst b/doc/tutorials/highgui/trackbar/trackbar.rst deleted file mode 100644 index fb922849ee..0000000000 --- a/doc/tutorials/highgui/trackbar/trackbar.rst +++ /dev/null @@ -1,154 +0,0 @@ -.. _Adding_Trackbars: - -Adding a Trackbar to our applications! -*************************************** - -* In the previous tutorials (about *linear blending* and the *brightness and contrast adjustments*) you might have noted that we needed to give some **input** to our programs, such as :math:`\alpha` and :math:`beta`. We accomplished that by entering this data using the Terminal - -* Well, it is time to use some fancy GUI tools. OpenCV provides some GUI utilities (*highgui.h*) for you. An example of this is a **Trackbar** - - .. image:: images/Adding_Trackbars_Tutorial_Trackbar.png - :alt: Trackbar example - :align: center - -* In this tutorial we will just modify our two previous programs so that they get the input information from the trackbar. - - -Goals -====== - -In this tutorial you will learn how to: - -* Add a Trackbar in an OpenCV window by using :create_trackbar:`createTrackbar <>` - -Code -===== - -Let's modify the program made in the tutorial :ref:`Adding_Images`. We will let the user enter the :math:`\alpha` value by using the Trackbar. - -.. code-block:: cpp - - #include - using namespace cv; - - /// Global Variables - const int alpha_slider_max = 100; - int alpha_slider; - double alpha; - double beta; - - /// Matrices to store images - Mat src1; - Mat src2; - Mat dst; - - /* - * @function on_trackbar - * @brief Callback for trackbar - */ - void on_trackbar( int, void* ) - { - alpha = (double) alpha_slider/alpha_slider_max ; - beta = ( 1.0 - alpha ); - - addWeighted( src1, alpha, src2, beta, 0.0, dst); - - imshow( "Linear Blend", dst ); - } - - int main( int argc, char** argv ) - { - /// Read image ( same size, same type ) - src1 = imread("../../images/LinuxLogo.jpg"); - src2 = imread("../../images/WindowsLogo.jpg"); - - if( !src1.data ) { printf("Error loading src1 \n"); return -1; } - if( !src2.data ) { printf("Error loading src2 \n"); return -1; } - - /// Initialize values - alpha_slider = 0; - - /// Create Windows - namedWindow("Linear Blend", 1); - - /// Create Trackbars - char TrackbarName[50]; - sprintf( TrackbarName, "Alpha x %d", alpha_slider_max ); - - createTrackbar( TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar ); - - /// Show some stuff - on_trackbar( alpha_slider, 0 ); - - /// Wait until user press some key - waitKey(0); - return 0; - } - - -Explanation -============ - -We only analyze the code that is related to Trackbar: - -#. First, we load 02 images, which are going to be blended. - - .. code-block:: cpp - - src1 = imread("../../images/LinuxLogo.jpg"); - src2 = imread("../../images/WindowsLogo.jpg"); - -#. To create a trackbar, first we have to create the window in which it is going to be located. So: - - .. code-block:: cpp - - namedWindow("Linear Blend", 1); - -#. Now we can create the Trackbar: - - .. code-block:: cpp - - createTrackbar( TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar ); - - Note the following: - - * Our Trackbar has a label **TrackbarName** - * The Trackbar is located in the window named **"Linear Blend"** - * The Trackbar values will be in the range from :math:`0` to **alpha_slider_max** (the minimum limit is always **zero**). - * The numerical value of Trackbar is stored in **alpha_slider** - * Whenever the user moves the Trackbar, the callback function **on_trackbar** is called - -#. Finally, we have to define the callback function **on_trackbar** - - .. code-block:: cpp - - void on_trackbar( int, void* ) - { - alpha = (double) alpha_slider/alpha_slider_max ; - beta = ( 1.0 - alpha ); - - addWeighted( src1, alpha, src2, beta, 0.0, dst); - - imshow( "Linear Blend", dst ); - } - - Note that: - - * We use the value of **alpha_slider** (integer) to get a double value for **alpha**. - * **alpha_slider** is updated each time the trackbar is displaced by the user. - * We define *src1*, *src2*, *dist*, *alpha*, *alpha_slider* and *beta* as global variables, so they can be used everywhere. - -Result -======= - -* Our program produces the following output: - - .. image:: images/Adding_Trackbars_Tutorial_Result_0.jpg - :alt: Adding Trackbars - Windows Linux - :align: center - -* As a manner of practice, you can also add 02 trackbars for the program made in :ref:`Basic_Linear_Transform`. One trackbar to set :math:`\alpha` and another for :math:`\beta`. The output might look like: - - .. image:: images/Adding_Trackbars_Tutorial_Result_1.jpg - :alt: Adding Trackbars - Lena - :align: center diff --git a/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.rst b/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.rst deleted file mode 100644 index eac1f24040..0000000000 --- a/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.rst +++ /dev/null @@ -1,216 +0,0 @@ -.. _videoInputPSNRMSSIM: - -Video Input with OpenCV and similarity measurement -************************************************** - -Goal -==== - -Today it is common to have a digital video recording system at your disposal. Therefore, you will eventually come to the situation that you no longer process a batch of images, but video streams. These may be of two kinds: real-time image feed (in the case of a webcam) or prerecorded and hard disk drive stored files. Luckily OpenCV threats these two in the same manner, with the same C++ class. So here's what you'll learn in this tutorial: - -.. container:: enumeratevisibleitemswithsquare - - + How to open and read video streams - + Two ways for checking image similarity: PSNR and SSIM - -The source code -=============== - -As a test case where to show off these using OpenCV I've created a small program that reads in two video files and performs a similarity check between them. This is something you could use to check just how well a new video compressing algorithms works. Let there be a reference (original) video like :download:`this small Megamind clip <../../../../samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind.avi>` and :download:`a compressed version of it <../../../../samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind_bugy.avi>`. You may also find the source code and these video file in the :file:`samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/` folder of the OpenCV source library. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video-input-psnr-ssim.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 1-15, 29-31, 33-208 - -How to read a video stream (online-camera or offline-file)? -=========================================================== - -Essentially, all the functionalities required for video manipulation is integrated in the :hgvideo:`VideoCapture ` C++ class. This on itself builds on the FFmpeg open source library. This is a basic dependency of OpenCV so you shouldn't need to worry about this. A video is composed of a succession of images, we refer to these in the literature as frames. In case of a video file there is a *frame rate* specifying just how long is between two frames. While for the video cameras usually there is a limit of just how many frames they can digitalize per second, this property is less important as at any time the camera sees the current snapshot of the world. - -The first task you need to do is to assign to a :hgvideo:`VideoCapture ` class its source. You can do this either via the :hgvideo:`constructor ` or its :hgvideo:`open ` function. If this argument is an integer then you will bind the class to a camera, a device. The number passed here is the ID of the device, assigned by the operating system. If you have a single camera attached to your system its ID will probably be zero and further ones increasing from there. If the parameter passed to these is a string it will refer to a video file, and the string points to the location and name of the file. For example, to the upper source code a valid command line is: - -.. code-block:: bash - - video/Megamind.avi video/Megamind_bug.avi 35 10 - -We do a similarity check. This requires a reference and a test case video file. The first two arguments refer to this. Here we use a relative address. This means that the application will look into its current working directory and open the video folder and try to find inside this the *Megamind.avi* and the *Megamind_bug.avi*. - -.. code-block:: cpp - - const string sourceReference = argv[1],sourceCompareWith = argv[2]; - - VideoCapture captRefrnc(sourceReference); - // or - VideoCapture captUndTst; - captUndTst.open(sourceCompareWith); - -To check if the binding of the class to a video source was successful or not use the :hgvideo:`isOpened ` function: - -.. code-block:: cpp - - if ( !captRefrnc.isOpened()) - { - cout << "Could not open reference " << sourceReference << endl; - return -1; - } - -Closing the video is automatic when the objects destructor is called. However, if you want to close it before this you need to call its :hgvideo:`release ` function. The frames of the video are just simple images. Therefore, we just need to extract them from the :hgvideo:`VideoCapture ` object and put them inside a *Mat* one. The video streams are sequential. You may get the frames one after another by the :hgvideo:`read ` or the overloaded >> operator: - -.. code-block:: cpp - - Mat frameReference, frameUnderTest; - captRefrnc >> frameReference; - captUndTst.open(frameUnderTest); - -The upper read operations will leave empty the *Mat* objects if no frame could be acquired (either cause the video stream was closed or you got to the end of the video file). We can check this with a simple if: - -.. code-block:: cpp - - if( frameReference.empty() || frameUnderTest.empty()) - { - // exit the program - } - -A read method is made of a frame grab and a decoding applied on that. You may call explicitly these two by using the :hgvideo:`grab ` and then the :hgvideo:`retrieve ` functions. - -Videos have many-many information attached to them besides the content of the frames. These are usually numbers, however in some case it may be short character sequences (4 bytes or less). Due to this to acquire these information there is a general function named :hgvideo:`get ` that returns double values containing these properties. Use bitwise operations to decode the characters from a double type and conversions where valid values are only integers. Its single argument is the ID of the queried property. For example, here we get the size of the frames in the reference and test case video file; plus the number of frames inside the reference. - -.. code-block:: cpp - - Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH), - (int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)), - - cout << "Reference frame resolution: Width=" << refS.width << " Height=" << refS.height - << " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl; - -When you are working with videos you may often want to control these values yourself. To do this there is a :hgvideo:`set ` function. Its first argument remains the name of the property you want to change and there is a second of double type containing the value to be set. It will return true if it succeeds and false otherwise. Good examples for this is seeking in a video file to a given time or frame: - -.. code-block:: cpp - - captRefrnc.set(CAP_PROP_POS_MSEC, 1.2); // go to the 1.2 second in the video - captRefrnc.set(CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video - // now a read operation would read the frame at the set position - -For properties you can read and change look into the documentation of the :hgvideo:`get ` and :hgvideo:`set ` functions. - - -Image similarity - PSNR and SSIM -================================ - -We want to check just how imperceptible our video converting operation went, therefore we need a system to check frame by frame the similarity or differences. The most common algorithm used for this is the PSNR (aka **Peak signal-to-noise ratio**). The simplest definition of this starts out from the *mean squad error*. Let there be two images: I1 and I2; with a two dimensional size i and j, composed of c number of channels. - -.. math:: - - MSE = \frac{1}{c*i*j} \sum{(I_1-I_2)^2} - -Then the PSNR is expressed as: - -.. math:: - - PSNR = 10 \cdot \log_{10} \left( \frac{MAX_I^2}{MSE} \right) - -Here the :math:`MAX_I^2` is the maximum valid value for a pixel. In case of the simple single byte image per pixel per channel this is 255. When two images are the same the MSE will give zero, resulting in an invalid divide by zero operation in the PSNR formula. In this case the PSNR is undefined and as we'll need to handle this case separately. The transition to a logarithmic scale is made because the pixel values have a very wide dynamic range. All this translated to OpenCV and a C++ function looks like: - -.. code-block:: cpp - - double getPSNR(const Mat& I1, const Mat& I2) - { - Mat s1; - absdiff(I1, I2, s1); // |I1 - I2| - s1.convertTo(s1, CV_32F); // cannot make a square on 8 bits - s1 = s1.mul(s1); // |I1 - I2|^2 - - Scalar s = sum(s1); // sum elements per channel - - double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels - - if( sse <= 1e-10) // for small values return zero - return 0; - else - { - double mse =sse /(double)(I1.channels() * I1.total()); - double psnr = 10.0*log10((255*255)/mse); - return psnr; - } - } - -Typically result values are anywhere between 30 and 50 for video compression, where higher is better. If the images significantly differ you'll get much lower ones like 15 and so. This similarity check is easy and fast to calculate, however in practice it may turn out somewhat inconsistent with human eye perception. The **structural similarity** algorithm aims to correct this. - -Describing the methods goes well beyond the purpose of this tutorial. For that I invite you to read the article introducing it. Nevertheless, you can get a good image of it by looking at the OpenCV implementation below. - -.. seealso:: - - SSIM is described more in-depth in the: "Z. Wang, A. C. Bovik, H. R. Sheikh and E. P. Simoncelli, "Image quality assessment: From error visibility to structural similarity," IEEE Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004." article. - -.. code-block:: cpp - - Scalar getMSSIM( const Mat& i1, const Mat& i2) - { - const double C1 = 6.5025, C2 = 58.5225; - /***************************** INITS **********************************/ - int d = CV_32F; - - Mat I1, I2; - i1.convertTo(I1, d); // cannot calculate on one byte large values - i2.convertTo(I2, d); - - Mat I2_2 = I2.mul(I2); // I2^2 - Mat I1_2 = I1.mul(I1); // I1^2 - Mat I1_I2 = I1.mul(I2); // I1 * I2 - - /***********************PRELIMINARY COMPUTING ******************************/ - - Mat mu1, mu2; // - GaussianBlur(I1, mu1, Size(11, 11), 1.5); - GaussianBlur(I2, mu2, Size(11, 11), 1.5); - - Mat mu1_2 = mu1.mul(mu1); - Mat mu2_2 = mu2.mul(mu2); - Mat mu1_mu2 = mu1.mul(mu2); - - Mat sigma1_2, sigma2_2, sigma12; - - GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5); - sigma1_2 -= mu1_2; - - GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5); - sigma2_2 -= mu2_2; - - GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5); - sigma12 -= mu1_mu2; - - ///////////////////////////////// FORMULA //////////////////////////////// - Mat t1, t2, t3; - - t1 = 2 * mu1_mu2 + C1; - t2 = 2 * sigma12 + C2; - t3 = t1.mul(t2); // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2)) - - t1 = mu1_2 + mu2_2 + C1; - t2 = sigma1_2 + sigma2_2 + C2; - t1 = t1.mul(t2); // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2)) - - Mat ssim_map; - divide(t3, t1, ssim_map); // ssim_map = t3./t1; - - Scalar mssim = mean( ssim_map ); // mssim = average of ssim map - return mssim; - } - -This will return a similarity index for each channel of the image. This value is between zero and one, where one corresponds to perfect fit. Unfortunately, the many Gaussian blurring is quite costly, so while the PSNR may work in a real time like environment (24 frame per second) this will take significantly more than to accomplish similar performance results. - -Therefore, the source code presented at the start of the tutorial will perform the PSNR measurement for each frame, and the SSIM only for the frames where the PSNR falls below an input value. For visualization purpose we show both images in an OpenCV window and print the PSNR and MSSIM values to the console. Expect to see something like: - -.. image:: images/outputVideoInput.png - :alt: A sample output - :align: center - -You may observe a runtime instance of this on the `YouTube here `_. - -.. raw:: html - -
- -
diff --git a/doc/tutorials/highgui/video-input-psnr-ssim/video_input_psnr_ssim.markdown b/doc/tutorials/highgui/video-input-psnr-ssim/video_input_psnr_ssim.markdown index 6d470a9728..b4464b403e 100644 --- a/doc/tutorials/highgui/video-input-psnr-ssim/video_input_psnr_ssim.markdown +++ b/doc/tutorials/highgui/video-input-psnr-ssim/video_input_psnr_ssim.markdown @@ -20,19 +20,12 @@ As a test case where to show off these using OpenCV I've created a small program video files and performs a similarity check between them. This is something you could use to check just how well a new video compressing algorithms works. Let there be a reference (original) video like [this small Megamind clip -](samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind.avi) and [a compressed -version of it ](samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind_bugy.avi). +](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind.avi) and [a compressed +version of it ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind_bugy.avi). You may also find the source code and these video file in the `samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/` folder of the OpenCV source library. -@dontinclude cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video-input-psnr-ssim.cpp - -@until Scalar getMSSIM -@skip main -@until { -@skip if -@until return mssim; -@until } +@includelineno cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video-input-psnr-ssim.cpp How to read a video stream (online-camera or offline-file)? ----------------------------------------------------------- diff --git a/doc/tutorials/highgui/video-write/video-write.rst b/doc/tutorials/highgui/video-write/video-write.rst deleted file mode 100644 index 36ecf88696..0000000000 --- a/doc/tutorials/highgui/video-write/video-write.rst +++ /dev/null @@ -1,136 +0,0 @@ -.. _videoWriteHighGui: - -Creating a video with OpenCV -**************************** - -Goal -==== - -Whenever you work with video feeds you may eventually want to save your image processing result in a form of a new video file. For simple video outputs you can use the OpenCV built-in :hgvideo:`VideoWriter ` class, designed for this. - -.. container:: enumeratevisibleitemswithsquare - - + How to create a video file with OpenCV - + What type of video files you can create with OpenCV - + How to extract a given color channel from a video - -As a simple demonstration I'll just extract one of the RGB color channels of an input video file into a new video. You can control the flow of the application from its console line arguments: - -.. container:: enumeratevisibleitemswithsquare - - + The first argument points to the video file to work on - + The second argument may be one of the characters: R G B. This will specify which of the channels to extract. - + The last argument is the character Y (Yes) or N (No). If this is no, the codec used for the input video file will be the same as for the output. Otherwise, a window will pop up and allow you to select yourself the codec to use. - -For example, a valid command line would look like: - -.. code-block:: bash - - video-write.exe video/Megamind.avi R Y - -The source code -=============== -You may also find the source code and these video file in the :file:`samples/cpp/tutorial_code/highgui/video-write/` folder of the OpenCV source library or :download:`download it from here <../../../../samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp>`. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp - :language: cpp - :linenos: - :tab-width: 4 - -The structure of a video -======================== -For start, you should have an idea of just how a video file looks. Every video file in itself is a container. The type of the container is expressed in the files extension (for example *avi*, *mov* or *mkv*). This contains multiple elements like: video feeds, audio feeds or other tracks (like for example subtitles). How these feeds are stored is determined by the codec used for each one of them. In case of the audio tracks commonly used codecs are *mp3* or *aac*. For the video files the list is somehow longer and includes names such as *XVID*, *DIVX*, *H264* or *LAGS* (*Lagarith Lossless Codec*). The full list of codecs you may use on a system depends on just what one you have installed. - -.. image:: images/videoFileStructure.png - :alt: The Structure of the video - :align: center - -As you can see things can get really complicated with videos. However, OpenCV is mainly a computer vision library, not a video stream, codec and write one. Therefore, the developers tried to keep this part as simple as possible. Due to this OpenCV for video containers supports only the *avi* extension, its first version. A direct limitation of this is that you cannot save a video file larger than 2 GB. Furthermore you can only create and expand a single video track inside the container. No audio or other track editing support here. Nevertheless, any video codec present on your system might work. If you encounter some of these limitations you will need to look into more specialized video writing libraries such as *FFMpeg* or codecs as *HuffYUV*, *CorePNG* and *LCL*. As an alternative, create the video track with OpenCV and expand it with sound tracks or convert it to other formats by using video manipulation programs such as *VirtualDub* or *AviSynth*. -The *VideoWriter* class -======================= -The content written here builds on the assumption you already read the :ref:`videoInputPSNRMSSIM` tutorial and you know how to read video files. -To create a video file you just need to create an instance of the :hgvideo:`VideoWriter ` class. You can specify its properties either via parameters in the constructor or later on via the :hgvideo:`open ` function. Either way, the parameters are the same: -1. The name of the output that contains the container type in its extension. At the moment only *avi* is supported. We construct this from the input file, add to this the name of the channel to use, and finish it off with the container extension. - - .. code-block:: cpp - - const string source = argv[1]; // the source file name - string::size_type pAt = source.find_last_of('.'); // Find extension point - const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi"; // Form the new name with container - -#. The codec to use for the video track. Now all the video codecs have a unique short name of maximum four characters. Hence, the *XVID*, *DIVX* or *H264* names. This is called a four character code. You may also ask this from an input video by using its *get* function. Because the *get* function is a general function it always returns double values. A double value is stored on 64 bits. Four characters are four bytes, meaning 32 bits. These four characters are coded in the lower 32 bits of the *double*. A simple way to throw away the upper 32 bits would be to just convert this value to *int*: - - .. code-block:: cpp - - VideoCapture inputVideo(source); // Open input - int ex = static_cast(inputVideo.get(CAP_PROP_FOURCC)); // Get Codec Type- Int form - - OpenCV internally works with this integer type and expect this as its second parameter. Now to convert from the integer form to string we may use two methods: a bitwise operator and a union method. The first one extracting from an int the characters looks like (an "and" operation, some shifting and adding a 0 at the end to close the string): - - .. code-block:: cpp - - char EXT[] = {ex & 0XFF , (ex & 0XFF00) >> 8,(ex & 0XFF0000) >> 16,(ex & 0XFF000000) >> 24, 0}; - - You can do the same thing with the *union* as: - - .. code-block:: cpp - - union { int v; char c[5];} uEx ; - uEx.v = ex; // From Int to char via union - uEx.c[4]='\0'; - - The advantage of this is that the conversion is done automatically after assigning, while for the bitwise operator you need to do the operations whenever you change the codec type. In case you know the codecs four character code beforehand, you can use the *CV_FOURCC* macro to build the integer: - - .. code-block::cpp - - CV_FOURCC('P','I','M,'1') // this is an MPEG1 codec from the characters to integer - - If you pass for this argument minus one than a window will pop up at runtime that contains all the codec installed on your system and ask you to select the one to use: - - .. image:: images/videoCompressSelect.png - :alt: Select the codec type to use - :align: center - -#. The frame per second for the output video. Again, here I keep the input videos frame per second by using the *get* function. -#. The size of the frames for the output video. Here too I keep the input videos frame size per second by using the *get* function. -#. The final argument is an optional one. By default is true and says that the output will be a colorful one (so for write you will send three channel images). To create a gray scale video pass a false parameter here. - -Here it is, how I use it in the sample: - - .. code-block:: cpp - - VideoWriter outputVideo; - Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH), //Acquire input size - (int) inputVideo.get(CAP_PROP_FRAME_HEIGHT)); - outputVideo.open(NAME , ex, inputVideo.get(CAP_PROP_FPS),S, true); - -Afterwards, you use the :hgvideo:`isOpened() ` function to find out if the open operation succeeded or not. The video file automatically closes when the *VideoWriter* object is destroyed. After you open the object with success you can send the frames of the video in a sequential order by using the :hgvideo:`write` function of the class. Alternatively, you can use its overloaded operator << : - -.. code-block:: cpp - - outputVideo.write(res); //or - outputVideo << res; - -Extracting a color channel from an RGB image means to set to zero the RGB values of the other channels. You can either do this with image scanning operations or by using the split and merge operations. You first split the channels up into different images, set the other channels to zero images of the same size and type and finally merge them back: - -.. code-block:: cpp - - split(src, spl); // process - extract only the correct channel - for( int i =0; i < 3; ++i) - if (i != channel) - spl[i] = Mat::zeros(S, spl[0].type()); - merge(spl, res); - -Put all this together and you'll get the upper source code, whose runtime result will show something around the idea: - -.. image:: images/resultOutputWideoWrite.png - :alt: A sample output - :align: center - -You may observe a runtime instance of this on the `YouTube here `_. - -.. raw:: html - -
- -
diff --git a/doc/tutorials/highgui/video-write/video_write.markdown b/doc/tutorials/highgui/video-write/video_write.markdown index 1c86e3771b..6d4f099d9c 100644 --- a/doc/tutorials/highgui/video-write/video_write.markdown +++ b/doc/tutorials/highgui/video-write/video_write.markdown @@ -31,7 +31,7 @@ The source code You may also find the source code and these video file in the `samples/cpp/tutorial_code/highgui/video-write/` folder of the OpenCV source library or [download it -from here ](samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp). +from here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp). @includelineno cpp/tutorial_code/HighGUI/video-write/video-write.cpp diff --git a/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.rst b/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.rst deleted file mode 100644 index ac81bcb859..0000000000 --- a/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.rst +++ /dev/null @@ -1,276 +0,0 @@ -.. _Morphology_1: - -Eroding and Dilating -********************** - -Goal -===== - -In this tutorial you will learn how to: - -* Apply two very common morphology operators: Dilation and Erosion. For this purpose, you will use the following OpenCV functions: - - * :erode:`erode <>` - * :dilate:`dilate <>` - -Cool Theory -============ - -.. note:: - The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. - -Morphological Operations --------------------------- - -* In short: A set of operations that process images based on shapes. Morphological operations apply a *structuring element* to an input image and generate an output image. - -* The most basic morphological operations are two: Erosion and Dilation. They have a wide array of uses, i.e. : - - * Removing noise - - * Isolation of individual elements and joining disparate elements in an image. - - * Finding of intensity bumps or holes in an image - -* We will explain dilation and erosion briefly, using the following image as an example: - - .. image:: images/Morphology_1_Tutorial_Theory_Original_Image.png - :alt: Original image - :align: center - -Dilation -~~~~~~~~ - -* This operations consists of convoluting an image :math:`A` with some kernel (:math:`B`), which can have any shape or size, usually a square or circle. - -* The kernel :math:`B` has a defined *anchor point*, usually being the center of the kernel. - -* As the kernel :math:`B` is scanned over the image, we compute the maximal pixel value overlapped by :math:`B` and replace the image pixel in the anchor point position with that maximal value. As you can deduce, this maximizing operation causes bright regions within an image to "grow" (therefore the name *dilation*). Take as an example the image above. Applying dilation we can get: - - .. image:: images/Morphology_1_Tutorial_Theory_Dilation.png - :alt: Dilation result - Theory example - :align: center - -The background (bright) dilates around the black regions of the letter. - -Erosion -~~~~~~~ - -* This operation is the sister of dilation. What this does is to compute a local minimum over the area of the kernel. - -* As the kernel :math:`B` is scanned over the image, we compute the minimal pixel value overlapped by :math:`B` and replace the image pixel under the anchor point with that minimal value. - -* Analagously to the example for dilation, we can apply the erosion operator to the original image (shown above). You can see in the result below that the bright areas of the image (the background, apparently), get thinner, whereas the dark zones (the "writing") gets bigger. - - .. image:: images/Morphology_1_Tutorial_Theory_Erosion.png - :alt: Erosion result - Theory example - :align: center - - -Code -====== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - #include "highgui.h" - #include - #include - - using namespace cv; - - /// Global variables - Mat src, erosion_dst, dilation_dst; - - int erosion_elem = 0; - int erosion_size = 0; - int dilation_elem = 0; - int dilation_size = 0; - int const max_elem = 2; - int const max_kernel_size = 21; - - /* Function Headers */ - void Erosion( int, void* ); - void Dilation( int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load an image - src = imread( argv[1] ); - - if( !src.data ) - { return -1; } - - /// Create windows - namedWindow( "Erosion Demo", WINDOW_AUTOSIZE ); - namedWindow( "Dilation Demo", WINDOW_AUTOSIZE ); - cvMoveWindow( "Dilation Demo", src.cols, 0 ); - - /// Create Erosion Trackbar - createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo", - &erosion_elem, max_elem, - Erosion ); - - createTrackbar( "Kernel size:\n 2n +1", "Erosion Demo", - &erosion_size, max_kernel_size, - Erosion ); - - /// Create Dilation Trackbar - createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo", - &dilation_elem, max_elem, - Dilation ); - - createTrackbar( "Kernel size:\n 2n +1", "Dilation Demo", - &dilation_size, max_kernel_size, - Dilation ); - - /// Default start - Erosion( 0, 0 ); - Dilation( 0, 0 ); - - waitKey(0); - return 0; - } - - /* @function Erosion */ - void Erosion( int, void* ) - { - int erosion_type; - if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; } - else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; } - else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; } - - Mat element = getStructuringElement( erosion_type, - Size( 2*erosion_size + 1, 2*erosion_size+1 ), - Point( erosion_size, erosion_size ) ); - - /// Apply the erosion operation - erode( src, erosion_dst, element ); - imshow( "Erosion Demo", erosion_dst ); - } - - /* @function Dilation */ - void Dilation( int, void* ) - { - int dilation_type; - if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; } - else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; } - else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; } - - Mat element = getStructuringElement( dilation_type, - Size( 2*dilation_size + 1, 2*dilation_size+1 ), - Point( dilation_size, dilation_size ) ); - /// Apply the dilation operation - dilate( src, dilation_dst, element ); - imshow( "Dilation Demo", dilation_dst ); - } - - -Explanation -============= - -#. Most of the stuff shown is known by you (if you have any doubt, please refer to the tutorials in previous sections). Let's check the general structure of the program: - - .. container:: enumeratevisibleitemswithsquare - - * Load an image (can be RGB or grayscale) - * Create two windows (one for dilation output, the other for erosion) - * Create a set of 02 Trackbars for each operation: - - * The first trackbar "Element" returns either **erosion_elem** or **dilation_elem** - * The second trackbar "Kernel size" return **erosion_size** or **dilation_size** for the corresponding operation. - - * Every time we move any slider, the user's function **Erosion** or **Dilation** will be called and it will update the output image based on the current trackbar values. - - Let's analyze these two functions: - -#. **erosion:** - - .. code-block:: cpp - - /* @function Erosion */ - void Erosion( int, void* ) - { - int erosion_type; - if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; } - else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; } - else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; } - - Mat element = getStructuringElement( erosion_type, - Size( 2*erosion_size + 1, 2*erosion_size+1 ), - Point( erosion_size, erosion_size ) ); - /// Apply the erosion operation - erode( src, erosion_dst, element ); - imshow( "Erosion Demo", erosion_dst ); - } - - * The function that performs the *erosion* operation is :erode:`erode <>`. As we can see, it receives three arguments: - - * *src*: The source image - * *erosion_dst*: The output image - * *element*: This is the kernel we will use to perform the operation. If we do not specify, the default is a simple :math:`3x3` matrix. Otherwise, we can specify its shape. For this, we need to use the function :get_structuring_element:`getStructuringElement <>`: - - .. code-block:: cpp - - Mat element = getStructuringElement( erosion_type, - Size( 2*erosion_size + 1, 2*erosion_size+1 ), - Point( erosion_size, erosion_size ) ); - - We can choose any of three shapes for our kernel: - - .. container:: enumeratevisibleitemswithsquare - - + Rectangular box: MORPH_RECT - + Cross: MORPH_CROSS - + Ellipse: MORPH_ELLIPSE - - Then, we just have to specify the size of our kernel and the *anchor point*. If not specified, it is assumed to be in the center. - - * That is all. We are ready to perform the erosion of our image. - - .. note:: - Additionally, there is another parameter that allows you to perform multiple erosions (iterations) at once. We are not using it in this simple tutorial, though. You can check out the Reference for more details. - - -#. **dilation:** - -The code is below. As you can see, it is completely similar to the snippet of code for **erosion**. Here we also have the option of defining our kernel, its anchor point and the size of the operator to be used. - -.. code-block:: cpp - - /* @function Dilation */ - void Dilation( int, void* ) - { - int dilation_type; - if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; } - else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; } - else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; } - - Mat element = getStructuringElement( dilation_type, - Size( 2*dilation_size + 1, 2*dilation_size+1 ), - Point( dilation_size, dilation_size ) ); - /// Apply the dilation operation - dilate( src, dilation_dst, element ); - imshow( "Dilation Demo", dilation_dst ); - } - - - -Results -======== - -* Compile the code above and execute it with an image as argument. For instance, using this image: - - .. image:: images/Morphology_1_Tutorial_Original_Image.jpg - :alt: Original image - :align: center - - We get the results below. Varying the indices in the Trackbars give different output images, naturally. Try them out! You can even try to add a third Trackbar to control the number of iterations. - - .. image:: images/Morphology_1_Result.jpg - :alt: Dilation and Erosion application - :align: center diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.rst b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.rst deleted file mode 100644 index e82a950d20..0000000000 --- a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.rst +++ /dev/null @@ -1,326 +0,0 @@ -.. _Smoothing: - -Smoothing Images -****************** - -Goal -===== - -In this tutorial you will learn how to apply diverse linear filters to smooth images using OpenCV functions such as: - -.. container:: enumeratevisibleitemswithsquare - - * :blur:`blur <>` - * :gaussian_blur:`GaussianBlur <>` - * :median_blur:`medianBlur <>` - * :bilateral_filter:`bilateralFilter <>` - -Theory -====== - -.. note:: - The explanation below belongs to the book `Computer Vision: Algorithms and Applications `_ by Richard Szeliski and to *LearningOpenCV* - -.. container:: enumeratevisibleitemswithsquare - - * *Smoothing*, also called *blurring*, is a simple and frequently used image processing operation. - - * There are many reasons for smoothing. In this tutorial we will focus on smoothing in order to reduce noise (other uses will be seen in the following tutorials). - - * To perform a smoothing operation we will apply a *filter* to our image. The most common type of filters are *linear*, in which an output pixel's value (i.e. :math:`g(i,j)`) is determined as a weighted sum of input pixel values (i.e. :math:`f(i+k,j+l)`) : - - .. math:: - g(i,j) = \sum_{k,l} f(i+k, j+l) h(k,l) - - :math:`h(k,l)` is called the *kernel*, which is nothing more than the coefficients of the filter. - - - It helps to visualize a *filter* as a window of coefficients sliding across the image. - - * There are many kind of filters, here we will mention the most used: - -Normalized Box Filter ------------------------ - -.. container:: enumeratevisibleitemswithsquare - - * This filter is the simplest of all! Each output pixel is the *mean* of its kernel neighbors ( all of them contribute with equal weights) - - * The kernel is below: - - .. math:: - - K = \dfrac{1}{K_{width} \cdot K_{height}} \begin{bmatrix} - 1 & 1 & 1 & ... & 1 \\ - 1 & 1 & 1 & ... & 1 \\ - . & . & . & ... & 1 \\ - . & . & . & ... & 1 \\ - 1 & 1 & 1 & ... & 1 - \end{bmatrix} - - -Gaussian Filter ---------------- - -.. container:: enumeratevisibleitemswithsquare - - * Probably the most useful filter (although not the fastest). Gaussian filtering is done by convolving each point in the input array with a *Gaussian kernel* and then summing them all to produce the output array. - - * Just to make the picture clearer, remember how a 1D Gaussian kernel look like? - - .. image:: images/Smoothing_Tutorial_theory_gaussian_0.jpg - :align: center - - Assuming that an image is 1D, you can notice that the pixel located in the middle would have the biggest weight. The weight of its neighbors decreases as the spatial distance between them and the center pixel increases. - -.. note:: - - Remember that a 2D Gaussian can be represented as : - - .. math:: - - G_{0}(x, y) = A e^{ \dfrac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } + \dfrac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } } - - where :math:`\mu` is the mean (the peak) and :math:`\sigma` represents the variance (per each of the variables :math:`x` and :math:`y`) - - -Median Filter --------------- - -The median filter run through each element of the signal (in this case the image) and replace each pixel with the **median** of its neighboring pixels (located in a square neighborhood around the evaluated pixel). - - -Bilateral Filter ------------------ - -.. container:: enumeratevisibleitemswithsquare - - * So far, we have explained some filters which main goal is to *smooth* an input image. However, sometimes the filters do not only dissolve the noise, but also smooth away the *edges*. To avoid this (at certain extent at least), we can use a bilateral filter. - - * In an analogous way as the Gaussian filter, the bilateral filter also considers the neighboring pixels with weights assigned to each of them. These weights have two components, the first of which is the same weighting used by the Gaussian filter. The second component takes into account the difference in intensity between the neighboring pixels and the evaluated one. - - * For a more detailed explanation you can check `this link `_ - - -Code -====== - -.. container:: enumeratevisibleitemswithsquare - - * **What does this program do?** - - .. container:: enumeratevisibleitemswithsquare - - * Loads an image - * Applies 4 different kinds of filters (explained in Theory) and show the filtered images sequentially - - * **Downloadable code**: - Click `here `_ - - * **Code at glance:** - - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - - using namespace std; - using namespace cv; - - /// Global Variables - int DELAY_CAPTION = 1500; - int DELAY_BLUR = 100; - int MAX_KERNEL_LENGTH = 31; - - Mat src; Mat dst; - char window_name[] = "Filter Demo 1"; - - /// Function headers - int display_caption( char* caption ); - int display_dst( int delay ); - - /* - * function main - */ - int main( int argc, char** argv ) - { - namedWindow( window_name, WINDOW_AUTOSIZE ); - - /// Load the source image - src = imread( "../images/lena.jpg", 1 ); - - if( display_caption( "Original Image" ) != 0 ) { return 0; } - - dst = src.clone(); - if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; } - - /// Applying Homogeneous blur - if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; } - - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { blur( src, dst, Size( i, i ), Point(-1,-1) ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - - /// Applying Gaussian blur - if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; } - - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { GaussianBlur( src, dst, Size( i, i ), 0, 0 ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - - /// Applying Median blur - if( display_caption( "Median Blur" ) != 0 ) { return 0; } - - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { medianBlur ( src, dst, i ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - - /// Applying Bilateral Filter - if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; } - - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { bilateralFilter ( src, dst, i, i*2, i/2 ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - - /// Wait until user press a key - display_caption( "End: Press a key!" ); - - waitKey(0); - return 0; - } - - int display_caption( char* caption ) - { - dst = Mat::zeros( src.size(), src.type() ); - putText( dst, caption, - Point( src.cols/4, src.rows/2), - FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) ); - - imshow( window_name, dst ); - int c = waitKey( DELAY_CAPTION ); - if( c >= 0 ) { return -1; } - return 0; - } - - int display_dst( int delay ) - { - imshow( window_name, dst ); - int c = waitKey ( delay ); - if( c >= 0 ) { return -1; } - return 0; - } - - - -Explanation -============= - -#. Let's check the OpenCV functions that involve only the smoothing procedure, since the rest is already known by now. - -#. **Normalized Block Filter:** - - OpenCV offers the function :blur:`blur <>` to perform smoothing with this filter. - - .. code-block:: cpp - - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { blur( src, dst, Size( i, i ), Point(-1,-1) ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - - - We specify 4 arguments (more details, check the Reference): - - .. container:: enumeratevisibleitemswithsquare - - + *src*: Source image - - + *dst*: Destination image - - + *Size( w,h )*: Defines the size of the kernel to be used ( of width *w* pixels and height *h* pixels) - - + *Point(-1, -1)*: Indicates where the anchor point (the pixel evaluated) is located with respect to the neighborhood. If there is a negative value, then the center of the kernel is considered the anchor point. - -#. **Gaussian Filter:** - - It is performed by the function :gaussian_blur:`GaussianBlur <>` : - - .. code-block:: cpp - - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { GaussianBlur( src, dst, Size( i, i ), 0, 0 ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - - Here we use 4 arguments (more details, check the OpenCV reference): - - .. container:: enumeratevisibleitemswithsquare - - + *src*: Source image - - + *dst*: Destination image - - + *Size(w, h)*: The size of the kernel to be used (the neighbors to be considered). :math:`w` and :math:`h` have to be odd and positive numbers otherwise thi size will be calculated using the :math:`\sigma_{x}` and :math:`\sigma_{y}` arguments. - - + :math:`\sigma_{x}`: The standard deviation in x. Writing :math:`0` implies that :math:`\sigma_{x}` is calculated using kernel size. - - + :math:`\sigma_{y}`: The standard deviation in y. Writing :math:`0` implies that :math:`\sigma_{y}` is calculated using kernel size. - - -#. **Median Filter:** - - This filter is provided by the :median_blur:`medianBlur <>` function: - - .. code-block:: cpp - - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { medianBlur ( src, dst, i ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - - We use three arguments: - - .. container:: enumeratevisibleitemswithsquare - - + *src*: Source image - - + *dst*: Destination image, must be the same type as *src* - - + *i*: Size of the kernel (only one because we use a square window). Must be odd. - - -#. **Bilateral Filter** - - Provided by OpenCV function :bilateral_filter:`bilateralFilter <>` - - .. code-block:: cpp - - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { bilateralFilter ( src, dst, i, i*2, i/2 ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - - We use 5 arguments: - - .. container:: enumeratevisibleitemswithsquare - - + *src*: Source image - - + *dst*: Destination image - - + *d*: The diameter of each pixel neighborhood. - - + :math:`\sigma_{Color}`: Standard deviation in the color space. - - + :math:`\sigma_{Space}`: Standard deviation in the coordinate space (in pixel terms) - - -Results -======== - -.. container:: enumeratevisibleitemswithsquare - - * The code opens an image (in this case *lena.jpg*) and display it under the effects of the 4 filters explained. - - * Here is a snapshot of the image smoothed using *medianBlur*: - - .. image:: images/Smoothing_Tutorial_Result_Median_Filter.jpg - :alt: Smoothing with a median filter - :align: center diff --git a/doc/tutorials/imgproc/histograms/back_projection/back_projection.rst b/doc/tutorials/imgproc/histograms/back_projection/back_projection.rst deleted file mode 100644 index 7138980f57..0000000000 --- a/doc/tutorials/imgproc/histograms/back_projection/back_projection.rst +++ /dev/null @@ -1,305 +0,0 @@ -.. _back_projection: - -Back Projection -**************** - - -Goal -==== - -In this tutorial you will learn: - -.. container:: enumeratevisibleitemswithsquare - - * What is Back Projection and why it is useful - - * How to use the OpenCV function :calc_back_project:`calcBackProject <>` to calculate Back Projection - - * How to mix different channels of an image by using the OpenCV function :mix_channels:`mixChannels <>` - - -Theory -====== - -What is Back Projection? ---------------------------- - -.. container:: enumeratevisibleitemswithsquare - - * Back Projection is a way of recording how well the pixels of a given image fit the distribution of pixels in a histogram model. - - * To make it simpler: For Back Projection, you calculate the histogram model of a feature and then use it to find this feature in an image. - - * Application example: If you have a histogram of flesh color (say, a Hue-Saturation histogram ), then you can use it to find flesh color areas in an image: - - -How does it work? ------------------- - -.. container:: enumeratevisibleitemswithsquare - - * We explain this by using the skin example: - - * Let's say you have gotten a skin histogram (Hue-Saturation) based on the image below. The histogram besides is going to be our *model histogram* (which we know represents a sample of skin tonality). You applied some mask to capture only the histogram of the skin area: - - ====== ====== - |T0| |T1| - ====== ====== - - .. |T0| image:: images/Back_Projection_Theory0.jpg - :align: middle - - .. |T1| image:: images/Back_Projection_Theory1.jpg - :align: middle - - - * Now, let's imagine that you get another hand image (Test Image) like the one below: (with its respective histogram): - - ====== ====== - |T2| |T3| - ====== ====== - - .. |T2| image:: images/Back_Projection_Theory2.jpg - :align: middle - - .. |T3| image:: images/Back_Projection_Theory3.jpg - :align: middle - - - * What we want to do is to use our *model histogram* (that we know represents a skin tonality) to detect skin areas in our Test Image. Here are the steps - - a. In each pixel of our Test Image (i.e. :math:`p(i,j)` ), collect the data and find the correspondent bin location for that pixel (i.e. :math:`( h_{i,j}, s_{i,j} )` ). - - b. Lookup the *model histogram* in the correspondent bin - :math:`( h_{i,j}, s_{i,j} )` - and read the bin value. - - c. Store this bin value in a new image (*BackProjection*). Also, you may consider to normalize the *model histogram* first, so the output for the Test Image can be visible for you. - - d. Applying the steps above, we get the following BackProjection image for our Test Image: - - .. image:: images/Back_Projection_Theory4.jpg - :align: center - - e. In terms of statistics, the values stored in *BackProjection* represent the *probability* that a pixel in *Test Image* belongs to a skin area, based on the *model histogram* that we use. For instance in our Test image, the brighter areas are more probable to be skin area (as they actually are), whereas the darker areas have less probability (notice that these "dark" areas belong to surfaces that have some shadow on it, which in turns affects the detection). - - -Code -==== - -.. container:: enumeratevisibleitemswithsquare - - * **What does this program do?** - - .. container:: enumeratevisibleitemswithsquare - - * Loads an image - * Convert the original to HSV format and separate only *Hue* channel to be used for the Histogram (using the OpenCV function :mix_channels:`mixChannels <>`) - * Let the user to enter the number of bins to be used in the calculation of the histogram. - * Calculate the histogram (and update it if the bins change) and the backprojection of the same image. - * Display the backprojection and the histogram in windows. - - * **Downloadable code**: - - a. Click `here `_ for the basic version (explained in this tutorial). - b. For stuff slightly fancier (using H-S histograms and floodFill to define a mask for the skin area) you can check the `improved demo `_ - c. ...or you can always check out the classical `camshiftdemo `_ in samples. - - * **Code at glance:** - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - - #include - - using namespace cv; - using namespace std; - - /// Global Variables - Mat src; Mat hsv; Mat hue; - int bins = 25; - - /// Function Headers - void Hist_and_Backproj(int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Read the image - src = imread( argv[1], 1 ); - /// Transform it to HSV - cvtColor( src, hsv, COLOR_BGR2HSV ); - - /// Use only the Hue value - hue.create( hsv.size(), hsv.depth() ); - int ch[] = { 0, 0 }; - mixChannels( &hsv, 1, &hue, 1, ch, 1 ); - - /// Create Trackbar to enter the number of bins - char* window_image = "Source image"; - namedWindow( window_image, WINDOW_AUTOSIZE ); - createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj ); - Hist_and_Backproj(0, 0); - - /// Show the image - imshow( window_image, src ); - - /// Wait until user exits the program - waitKey(0); - return 0; - } - - - /* - * @function Hist_and_Backproj - * @brief Callback to Trackbar - */ - void Hist_and_Backproj(int, void* ) - { - MatND hist; - int histSize = MAX( bins, 2 ); - float hue_range[] = { 0, 180 }; - const float* ranges = { hue_range }; - - /// Get the Histogram and normalize it - calcHist( &hue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false ); - normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() ); - - /// Get Backprojection - MatND backproj; - calcBackProject( &hue, 1, 0, hist, backproj, &ranges, 1, true ); - - /// Draw the backproj - imshow( "BackProj", backproj ); - - /// Draw the histogram - int w = 400; int h = 400; - int bin_w = cvRound( (double) w / histSize ); - Mat histImg = Mat::zeros( w, h, CV_8UC3 ); - - for( int i = 0; i < bins; i ++ ) - { rectangle( histImg, Point( i*bin_w, h ), Point( (i+1)*bin_w, h - cvRound( hist.at(i)*h/255.0 ) ), Scalar( 0, 0, 255 ), -1 ); } - - imshow( "Histogram", histImg ); - } - -Explanation -=========== - -#. Declare the matrices to store our images and initialize the number of bins to be used by our histogram: - - .. code-block:: cpp - - Mat src; Mat hsv; Mat hue; - int bins = 25; - -#. Read the input image and transform it to HSV format: - - .. code-block:: cpp - - src = imread( argv[1], 1 ); - cvtColor( src, hsv, COLOR_BGR2HSV ); - -#. For this tutorial, we will use only the Hue value for our 1-D histogram (check out the fancier code in the links above if you want to use the more standard H-S histogram, which yields better results): - - .. code-block:: cpp - - hue.create( hsv.size(), hsv.depth() ); - int ch[] = { 0, 0 }; - mixChannels( &hsv, 1, &hue, 1, ch, 1 ); - - as you see, we use the function :mix_channels:`mixChannels` to get only the channel 0 (Hue) from the hsv image. It gets the following parameters: - - .. container:: enumeratevisibleitemswithsquare - - + **&hsv:** The source array from which the channels will be copied - + **1:** The number of source arrays - + **&hue:** The destination array of the copied channels - + **1:** The number of destination arrays - + **ch[] = {0,0}:** The array of index pairs indicating how the channels are copied. In this case, the Hue(0) channel of &hsv is being copied to the 0 channel of &hue (1-channel) - + **1:** Number of index pairs - -#. Create a Trackbar for the user to enter the bin values. Any change on the Trackbar means a call to the **Hist_and_Backproj** callback function. - - .. code-block:: cpp - - char* window_image = "Source image"; - namedWindow( window_image, WINDOW_AUTOSIZE ); - createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj ); - Hist_and_Backproj(0, 0); - -#. Show the image and wait for the user to exit the program: - - .. code-block:: cpp - - imshow( window_image, src ); - - waitKey(0); - return 0; - -#. **Hist_and_Backproj function:** Initialize the arguments needed for :calc_hist:`calcHist <>`. The number of bins comes from the Trackbar: - - - .. code-block:: cpp - - void Hist_and_Backproj(int, void* ) - { - MatND hist; - int histSize = MAX( bins, 2 ); - float hue_range[] = { 0, 180 }; - const float* ranges = { hue_range }; - -#. Calculate the Histogram and normalize it to the range :math:`[0,255]` - - .. code-block:: cpp - - calcHist( &hue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false ); - normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() ); - -#. Get the Backprojection of the same image by calling the function :calc_back_project:`calcBackProject <>` - - .. code-block:: cpp - - MatND backproj; - calcBackProject( &hue, 1, 0, hist, backproj, &ranges, 1, true ); - - all the arguments are known (the same as used to calculate the histogram), only we add the backproj matrix, which will store the backprojection of the source image (&hue) - -#. Display backproj: - - .. code-block:: cpp - - imshow( "BackProj", backproj ); - -#. Draw the 1-D Hue histogram of the image: - - .. code-block:: cpp - - int w = 400; int h = 400; - int bin_w = cvRound( (double) w / histSize ); - Mat histImg = Mat::zeros( w, h, CV_8UC3 ); - - for( int i = 0; i < bins; i ++ ) - { rectangle( histImg, Point( i*bin_w, h ), Point( (i+1)*bin_w, h - cvRound( hist.at(i)*h/255.0 ) ), Scalar( 0, 0, 255 ), -1 ); } - - imshow( "Histogram", histImg ); - - - -Results -======= - -#. Here are the output by using a sample image ( guess what? Another hand ). You can play with the bin values and you will observe how it affects the results: - - ====== ====== ====== - |R0| |R1| |R2| - ====== ====== ====== - - .. |R0| image:: images/Back_Projection1_Source_Image.jpg - :align: middle - - .. |R1| image:: images/Back_Projection1_Histogram.jpg - :align: middle - - .. |R2| image:: images/Back_Projection1_BackProj.jpg - :align: middle diff --git a/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.rst b/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.rst deleted file mode 100644 index acc0e8cc2c..0000000000 --- a/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.rst +++ /dev/null @@ -1,331 +0,0 @@ -.. _histogram_calculation: - -Histogram Calculation -********************* - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :split:`split <>` to divide an image into its correspondent planes. - - * To calculate histograms of arrays of images by using the OpenCV function :calc_hist:`calcHist <>` - - * To normalize an array by using the function :normalize:`normalize <>` - - -.. note:: - In the last tutorial (:ref:`histogram_equalization`) we talked about a particular kind of histogram called *Image histogram*. Now we will considerate it in its more general concept. Read on! - - -What are histograms? --------------------- - -.. container:: enumeratevisibleitemswithsquare - - * Histograms are collected *counts* of data organized into a set of predefined *bins* - - * When we say *data* we are not restricting it to be intensity values (as we saw in the previous Tutorial). The data collected can be whatever feature you find useful to describe your image. - - * Let's see an example. Imagine that a Matrix contains information of an image (i.e. intensity in the range :math:`0-255`): - - - .. image:: images/Histogram_Calculation_Theory_Hist0.jpg - :align: center - - * What happens if we want to *count* this data in an organized way? Since we know that the *range* of information value for this case is 256 values, we can segment our range in subparts (called **bins**) like: - - .. math:: - \begin{array}{l} - [0, 255] = { [0, 15] \cup [16, 31] \cup ....\cup [240,255] } \\ - range = { bin_{1} \cup bin_{2} \cup ....\cup bin_{n = 15} } - \end{array} - - and we can keep count of the number of pixels that fall in the range of each :math:`bin_{i}`. Applying this to the example above we get the image below ( axis x represents the bins and axis y the number of pixels in each of them). - - - .. image:: images/Histogram_Calculation_Theory_Hist1.jpg - :align: center - - * This was just a simple example of how an histogram works and why it is useful. An histogram can keep count not only of color intensities, but of whatever image features that we want to measure (i.e. gradients, directions, etc). - - * Let's identify some parts of the histogram: - - a. **dims**: The number of parameters you want to collect data of. In our example, **dims = 1** because we are only counting the intensity values of each pixel (in a greyscale image). - b. **bins**: It is the number of **subdivisions** in each dim. In our example, **bins = 16** - c. **range**: The limits for the values to be measured. In this case: **range = [0,255]** - - * What if you want to count two features? In this case your resulting histogram would be a 3D plot (in which x and y would be :math:`bin_{x}` and :math:`bin_{y}` for each feature and z would be the number of counts for each combination of :math:`(bin_{x}, bin_{y})`. The same would apply for more features (of course it gets trickier). - - -What OpenCV offers you ------------------------ - -For simple purposes, OpenCV implements the function :calc_hist:`calcHist <>`, which calculates the histogram of a set of arrays (usually images or image planes). It can operate with up to 32 dimensions. We will see it in the code below! - - -Code -==== - -.. container:: enumeratevisibleitemswithsquare - - * **What does this program do?** - - .. container:: enumeratevisibleitemswithsquare - - * Loads an image - * Splits the image into its R, G and B planes using the function :split:`split <>` - * Calculate the Histogram of each 1-channel plane by calling the function :calc_hist:`calcHist <>` - * Plot the three histograms in a window - - * **Downloadable code**: - Click `here `_ - - * **Code at glance:** - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - - using namespace std; - using namespace cv; - - /* - * @function main - */ - int main( int argc, char** argv ) - { - Mat src, dst; - - /// Load image - src = imread( argv[1], 1 ); - - if( !src.data ) - { return -1; } - - /// Separate the image in 3 places ( B, G and R ) - vector bgr_planes; - split( src, bgr_planes ); - - /// Establish the number of bins - int histSize = 256; - - /// Set the ranges ( for B,G,R) ) - float range[] = { 0, 256 } ; - const float* histRange = { range }; - - bool uniform = true; bool accumulate = false; - - Mat b_hist, g_hist, r_hist; - - /// Compute the histograms: - calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate ); - calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate ); - calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate ); - - // Draw the histograms for B, G and R - int hist_w = 512; int hist_h = 400; - int bin_w = cvRound( (double) hist_w/histSize ); - - Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) ); - - /// Normalize the result to [ 0, histImage.rows ] - normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); - normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); - normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); - - /// Draw for each channel - for( int i = 1; i < histSize; i++ ) - { - line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at(i-1)) ) , - Point( bin_w*(i), hist_h - cvRound(b_hist.at(i)) ), - Scalar( 255, 0, 0), 2, 8, 0 ); - line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at(i-1)) ) , - Point( bin_w*(i), hist_h - cvRound(g_hist.at(i)) ), - Scalar( 0, 255, 0), 2, 8, 0 ); - line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at(i-1)) ) , - Point( bin_w*(i), hist_h - cvRound(r_hist.at(i)) ), - Scalar( 0, 0, 255), 2, 8, 0 ); - } - - /// Display - namedWindow("calcHist Demo", WINDOW_AUTOSIZE ); - imshow("calcHist Demo", histImage ); - - waitKey(0); - - return 0; - } - -Explanation -=========== - -#. Create the necessary matrices: - - .. code-block:: cpp - - Mat src, dst; - -#. Load the source image - - .. code-block:: cpp - - src = imread( argv[1], 1 ); - - if( !src.data ) - { return -1; } - -#. Separate the source image in its three R,G and B planes. For this we use the OpenCV function :split:`split <>`: - - .. code-block:: cpp - - vector bgr_planes; - split( src, bgr_planes ); - - our input is the image to be divided (this case with three channels) and the output is a vector of Mat ) - -#. Now we are ready to start configuring the **histograms** for each plane. Since we are working with the B, G and R planes, we know that our values will range in the interval :math:`[0,255]` - - a. Establish number of bins (5, 10...): - - .. code-block:: cpp - - int histSize = 256; //from 0 to 255 - - b. Set the range of values (as we said, between 0 and 255 ) - - .. code-block:: cpp - - /// Set the ranges ( for B,G,R) ) - float range[] = { 0, 256 } ; //the upper boundary is exclusive - const float* histRange = { range }; - - c. We want our bins to have the same size (uniform) and to clear the histograms in the beginning, so: - - .. code-block:: cpp - - bool uniform = true; bool accumulate = false; - - d. Finally, we create the Mat objects to save our histograms. Creating 3 (one for each plane): - - .. code-block:: cpp - - Mat b_hist, g_hist, r_hist; - - e. We proceed to calculate the histograms by using the OpenCV function :calc_hist:`calcHist <>`: - - .. code-block:: cpp - - /// Compute the histograms: - calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate ); - calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate ); - calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate ); - - where the arguments are: - - .. container:: enumeratevisibleitemswithsquare - - + **&bgr_planes[0]:** The source array(s) - + **1**: The number of source arrays (in this case we are using 1. We can enter here also a list of arrays ) - + **0**: The channel (*dim*) to be measured. In this case it is just the intensity (each array is single-channel) so we just write 0. - + **Mat()**: A mask to be used on the source array ( zeros indicating pixels to be ignored ). If not defined it is not used - + **b_hist**: The Mat object where the histogram will be stored - + **1**: The histogram dimensionality. - + **histSize:** The number of bins per each used dimension - + **histRange:** The range of values to be measured per each dimension - + **uniform** and **accumulate**: The bin sizes are the same and the histogram is cleared at the beginning. - - -#. Create an image to display the histograms: - - .. code-block:: cpp - - // Draw the histograms for R, G and B - int hist_w = 512; int hist_h = 400; - int bin_w = cvRound( (double) hist_w/histSize ); - - Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) ); - -#. Notice that before drawing, we first :normalize:`normalize <>` the histogram so its values fall in the range indicated by the parameters entered: - - .. code-block:: cpp - - /// Normalize the result to [ 0, histImage.rows ] - normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); - normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); - normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); - - this function receives these arguments: - - .. container:: enumeratevisibleitemswithsquare - - + **b_hist:** Input array - + **b_hist:** Output normalized array (can be the same) - + **0** and**histImage.rows**: For this example, they are the lower and upper limits to normalize the values of **r_hist** - + **NORM_MINMAX:** Argument that indicates the type of normalization (as described above, it adjusts the values between the two limits set before) - + **-1:** Implies that the output normalized array will be the same type as the input - + **Mat():** Optional mask - -#. Finally, observe that to access the bin (in this case in this 1D-Histogram): - - .. code-block:: cpp - - /// Draw for each channel - for( int i = 1; i < histSize; i++ ) - { - line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at(i-1)) ) , - Point( bin_w*(i), hist_h - cvRound(b_hist.at(i)) ), - Scalar( 255, 0, 0), 2, 8, 0 ); - line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at(i-1)) ) , - Point( bin_w*(i), hist_h - cvRound(g_hist.at(i)) ), - Scalar( 0, 255, 0), 2, 8, 0 ); - line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at(i-1)) ) , - Point( bin_w*(i), hist_h - cvRound(r_hist.at(i)) ), - Scalar( 0, 0, 255), 2, 8, 0 ); - } - - - we use the expression: - - .. code-block:: cpp - - b_hist.at(i) - - - where :math:`i` indicates the dimension. If it were a 2D-histogram we would use something like: - - .. code-block:: cpp - - b_hist.at( i, j ) - - -#. Finally we display our histograms and wait for the user to exit: - - .. code-block:: cpp - - namedWindow("calcHist Demo", WINDOW_AUTOSIZE ); - imshow("calcHist Demo", histImage ); - - waitKey(0); - - return 0; - - -Result -====== - -#. Using as input argument an image like the shown below: - - .. image:: images/Histogram_Calculation_Original_Image.jpg - :align: center - -#. Produces the following histogram: - - .. image:: images/Histogram_Calculation_Result.jpg - :align: center diff --git a/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.rst b/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.rst deleted file mode 100644 index 8bb72da9ff..0000000000 --- a/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.rst +++ /dev/null @@ -1,221 +0,0 @@ -.. _histogram_comparison: - -Histogram Comparison -******************** - -Goal -==== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the function :compare_hist:`compareHist <>` to get a numerical parameter that express how well two histograms match with each other. - * Use different metrics to compare histograms - - -Theory -====== - -.. container:: enumeratevisibleitemswithsquare - - * To compare two histograms ( :math:`H_{1}` and :math:`H_{2}` ), first we have to choose a *metric* (:math:`d(H_{1}, H_{2})`) to express how well both histograms match. - - * OpenCV implements the function :compare_hist:`compareHist <>` to perform a comparison. It also offers 4 different metrics to compute the matching: - - - a. **Correlation ( CV\_COMP\_CORREL )** - - .. math:: - - d(H_1,H_2) = \frac{\sum_I (H_1(I) - \bar{H_1}) (H_2(I) - \bar{H_2})}{\sqrt{\sum_I(H_1(I) - \bar{H_1})^2 \sum_I(H_2(I) - \bar{H_2})^2}} - - where - - .. math:: - - \bar{H_k} = \frac{1}{N} \sum _J H_k(J) - - - and :math:`N` is the total number of histogram bins. - - - - b. **Chi-Square ( CV\_COMP\_CHISQR )** - - .. math:: - - d(H_1,H_2) = \sum _I \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)} - - - c. **Intersection ( method=CV\_COMP\_INTERSECT )** - - .. math:: - - d(H_1,H_2) = \sum _I \min (H_1(I), H_2(I)) - - - d. **Bhattacharyya distance ( CV\_COMP\_BHATTACHARYYA )** - - .. math:: - - d(H_1,H_2) = \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}} \sum_I \sqrt{H_1(I) \cdot H_2(I)}} - - - -Code -==== - -.. container:: enumeratevisibleitemswithsquare - - * **What does this program do?** - - .. container:: enumeratevisibleitemswithsquare - - * Loads a *base image* and 2 *test images* to be compared with it. - * Generate 1 image that is the lower half of the *base image* - * Convert the images to HSV format - * Calculate the H-S histogram for all the images and normalize them in order to compare them. - * Compare the histogram of the *base image* with respect to the 2 test histograms, the histogram of the lower half base image and with the same base image histogram. - * Display the numerical matching parameters obtained. - - * **Downloadable code**: - Click `here `_ - - * **Code at glance:** - -.. literalinclude:: ../../../../../samples/cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp - :language: cpp - :tab-width: 4 - - - -Explanation -=========== - -#. Declare variables such as the matrices to store the base image and the two other images to compare ( RGB and HSV ) - - .. code-block:: cpp - - Mat src_base, hsv_base; - Mat src_test1, hsv_test1; - Mat src_test2, hsv_test2; - Mat hsv_half_down; - -#. Load the base image (src\_base) and the other two test images: - - .. code-block:: cpp - - if( argc < 4 ) - { printf("** Error. Usage: ./compareHist_Demo \n"); - return -1; - } - - src_base = imread( argv[1], 1 ); - src_test1 = imread( argv[2], 1 ); - src_test2 = imread( argv[3], 1 ); - -#. Convert them to HSV format: - - .. code-block:: cpp - - cvtColor( src_base, hsv_base, COLOR_BGR2HSV ); - cvtColor( src_test1, hsv_test1, COLOR_BGR2HSV ); - cvtColor( src_test2, hsv_test2, COLOR_BGR2HSV ); - -#. Also, create an image of half the base image (in HSV format): - - .. code-block:: cpp - - hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) ); - -#. Initialize the arguments to calculate the histograms (bins, ranges and channels H and S ). - - .. code-block:: cpp - - int h_bins = 50; int s_bins = 60; - int histSize[] = { h_bins, s_bins }; - - float h_ranges[] = { 0, 180 }; - float s_ranges[] = { 0, 256 }; - - const float* ranges[] = { h_ranges, s_ranges }; - - int channels[] = { 0, 1 }; - -#. Create the MatND objects to store the histograms: - - .. code-block:: cpp - - MatND hist_base; - MatND hist_half_down; - MatND hist_test1; - MatND hist_test2; - -#. Calculate the Histograms for the base image, the 2 test images and the half-down base image: - - .. code-block:: cpp - - calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false ); - normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat() ); - - calcHist( &hsv_half_down, 1, channels, Mat(), hist_half_down, 2, histSize, ranges, true, false ); - normalize( hist_half_down, hist_half_down, 0, 1, NORM_MINMAX, -1, Mat() ); - - calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false ); - normalize( hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat() ); - - calcHist( &hsv_test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false ); - normalize( hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat() ); - - -#. Apply sequentially the 4 comparison methods between the histogram of the base image (hist\_base) and the other histograms: - - .. code-block:: cpp - - for( int i = 0; i < 4; i++ ) - { int compare_method = i; - double base_base = compareHist( hist_base, hist_base, compare_method ); - double base_half = compareHist( hist_base, hist_half_down, compare_method ); - double base_test1 = compareHist( hist_base, hist_test1, compare_method ); - double base_test2 = compareHist( hist_base, hist_test2, compare_method ); - - printf( " Method [%d] Perfect, Base-Half, Base-Test(1), Base-Test(2) : %f, %f, %f, %f \n", i, base_base, base_half , base_test1, base_test2 ); - } - - -Results -======== - -#. We use as input the following images: - - ============ ============ ============ - |Base_0| |Test_1| |Test_2| - ============ ============ ============ - - .. |Base_0| image:: images/Histogram_Comparison_Source_0.jpg - :align: middle - - .. |Test_1| image:: images/Histogram_Comparison_Source_1.jpg - :align: middle - - .. |Test_2| image:: images/Histogram_Comparison_Source_2.jpg - :align: middle - - where the first one is the base (to be compared to the others), the other 2 are the test images. We will also compare the first image with respect to itself and with respect of half the base image. - -#. We should expect a perfect match when we compare the base image histogram with itself. Also, compared with the histogram of half the base image, it should present a high match since both are from the same source. For the other two test images, we can observe that they have very different lighting conditions, so the matching should not be very good: - -#. Here the numeric results: - - =============== =============== =============== =============== =============== - *Method* Base - Base Base - Half Base - Test 1 Base - Test 2 - =============== =============== =============== =============== =============== - *Correlation* 1.000000 0.930766 0.182073 0.120447 - *Chi-square* 0.000000 4.940466 21.184536 49.273437 - *Intersection* 24.391548 14.959809 3.889029 5.775088 - *Bhattacharyya* 0.000000 0.222609 0.646576 0.801869 - =============== =============== =============== =============== =============== - - - For the *Correlation* and *Intersection* methods, the higher the metric, the more accurate the match. As we can see, the match *base-base* is the highest of all as expected. Also we can observe that the match *base-half* is the second best match (as we predicted). For the other two metrics, the less the result, the better the match. We can observe that the matches between the test 1 and test 2 with respect to the base are worse, which again, was expected. diff --git a/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.rst b/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.rst deleted file mode 100644 index 076809304a..0000000000 --- a/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.rst +++ /dev/null @@ -1,217 +0,0 @@ -.. _histogram_equalization: - -Histogram Equalization -********************** - -Goal -==== - -In this tutorial you will learn: - -.. container:: enumeratevisibleitemswithsquare - - * What an image histogram is and why it is useful - - * To equalize histograms of images by using the OpenCV function:equalize_hist:`equalizeHist <>` - - - -Theory -====== - -What is an Image Histogram? ---------------------------- - -.. container:: enumeratevisibleitemswithsquare - - * It is a graphical representation of the intensity distribution of an image. - - * It quantifies the number of pixels for each intensity value considered. - -.. image:: images/Histogram_Equalization_Theory_0.jpg - :align: center - - -What is Histogram Equalization? -------------------------------- - -.. container:: enumeratevisibleitemswithsquare - - * It is a method that improves the contrast in an image, in order to stretch out the intensity range. - - * To make it clearer, from the image above, you can see that the pixels seem clustered around the middle of the available range of intensities. What Histogram Equalization does is to *stretch out* this range. Take a look at the figure below: The green circles indicate the *underpopulated* intensities. After applying the equalization, we get an histogram like the figure in the center. The resulting image is shown in the picture at right. - -.. image:: images/Histogram_Equalization_Theory_1.jpg - :align: center - -How does it work? ------------------ - -.. container:: enumeratevisibleitemswithsquare - - * Equalization implies *mapping* one distribution (the given histogram) to another distribution (a wider and more uniform distribution of intensity values) so the intensity values are spreaded over the whole range. - - * To accomplish the equalization effect, the remapping should be the *cumulative distribution function (cdf)* (more details, refer to *Learning OpenCV*). For the histogram :math:`H(i)`, its *cumulative distribution* :math:`H^{'}(i)` is: - - .. math:: - - H^{'}(i) = \sum_{0 \le j < i} H(j) - - To use this as a remapping function, we have to normalize :math:`H^{'}(i)` such that the maximum value is 255 ( or the maximum value for the intensity of the image ). From the example above, the cumulative function is: - - .. image:: images/Histogram_Equalization_Theory_2.jpg - :align: center - - * Finally, we use a simple remapping procedure to obtain the intensity values of the equalized image: - - .. math:: - - equalized( x, y ) = H^{'}( src(x,y) ) - -Code -==== - -.. container:: enumeratevisibleitemswithsquare - - * **What does this program do?** - - .. container:: enumeratevisibleitemswithsquare - - * Loads an image - * Convert the original image to grayscale - * Equalize the Histogram by using the OpenCV function :equalize_hist:`EqualizeHist <>` - * Display the source and equalized images in a window. - - * **Downloadable code**: - Click `here `_ - - * **Code at glance:** - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - - using namespace cv; - using namespace std; - - /* @function main */ - int main( int argc, char** argv ) - { - Mat src, dst; - - char* source_window = "Source image"; - char* equalized_window = "Equalized Image"; - - /// Load image - src = imread( argv[1], 1 ); - - if( !src.data ) - { cout<<"Usage: ./Histogram_Demo "<"<` : - - .. code-block:: cpp - - equalizeHist( src, dst ); - - As it can be easily seen, the only arguments are the original image and the output (equalized) image. - -#. Display both images (original and equalized) : - - .. code-block:: cpp - - namedWindow( source_window, WINDOW_AUTOSIZE ); - namedWindow( equalized_window, WINDOW_AUTOSIZE ); - - imshow( source_window, src ); - imshow( equalized_window, dst ); - -#. Wait until user exists the program - - .. code-block:: cpp - - waitKey(0); - return 0; - - -Results -======= - -#. To appreciate better the results of equalization, let's introduce an image with not much contrast, such as: - - .. image:: images/Histogram_Equalization_Original_Image.jpg - :align: center - - which, by the way, has this histogram: - - .. image:: images/Histogram_Equalization_Original_Histogram.jpg - :align: center - - notice that the pixels are clustered around the center of the histogram. - -#. After applying the equalization with our program, we get this result: - - .. image:: images/Histogram_Equalization_Equalized_Image.jpg - :align: center - - this image has certainly more contrast. Check out its new histogram like this: - - .. image:: images/Histogram_Equalization_Equalized_Histogram.jpg - :align: center - - Notice how the number of pixels is more distributed through the intensity range. - - -.. note:: - Are you wondering how did we draw the Histogram figures shown above? Check out the following tutorial! diff --git a/doc/tutorials/imgproc/histograms/template_matching/template_matching.rst b/doc/tutorials/imgproc/histograms/template_matching/template_matching.rst deleted file mode 100644 index fdd5698f6e..0000000000 --- a/doc/tutorials/imgproc/histograms/template_matching/template_matching.rst +++ /dev/null @@ -1,371 +0,0 @@ -.. _template_matching: - -Template Matching -***************** - -Goal -==== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :match_template:`matchTemplate <>` to search for matches between an image patch and an input image - * Use the OpenCV function :min_max_loc:`minMaxLoc <>` to find the maximum and minimum values (as well as their positions) in a given array. - -Theory -====== - -What is template matching? --------------------------- - -.. container:: enumeratevisibleitemswithsquare - - Template matching is a technique for finding areas of an image that match (are similar) to a template image (patch). - - -How does it work? ------------------- - -.. container:: enumeratevisibleitemswithsquare - - * We need two primary components: - - a. **Source image (I):** The image in which we expect to find a match to the template image - b. **Template image (T):** The patch image which will be compared to the template image - - our goal is to detect the highest matching area: - - .. image:: images/Template_Matching_Template_Theory_Summary.jpg - :align: center - - * To identify the matching area, we have to *compare* the template image against the source image by sliding it: - - .. image:: images/Template_Matching_Template_Theory_Sliding.jpg - :align: center - - * By **sliding**, we mean moving the patch one pixel at a time (left to right, up to down). At each location, a metric is calculated so it represents how "good" or "bad" the match at that location is (or how similar the patch is to that particular area of the source image). - - * For each location of **T** over **I**, you *store* the metric in the *result matrix* **(R)**. Each location :math:`(x,y)` in **R** contains the match metric: - - .. image:: images/Template_Matching_Template_Theory_Result.jpg - :align: center - - the image above is the result **R** of sliding the patch with a metric **TM_CCORR_NORMED**. The brightest locations indicate the highest matches. As you can see, the location marked by the red circle is probably the one with the highest value, so that location (the rectangle formed by that point as a corner and width and height equal to the patch image) is considered the match. - - * In practice, we use the function :min_max_loc:`minMaxLoc <>` to locate the highest value (or lower, depending of the type of matching method) in the *R* matrix. - -Which are the matching methods available in OpenCV? ----------------------------------------------------- - -Good question. OpenCV implements Template matching in the function :match_template:`matchTemplate <>`. The available methods are 6: - -a. **method=CV\_TM\_SQDIFF** - - .. math:: - - R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2 - - -b. **method=CV\_TM\_SQDIFF\_NORMED** - - .. math:: - - R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} - - -c. **method=CV\_TM\_CCORR** - - .. math:: - - R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y')) - - -d. **method=CV\_TM\_CCORR\_NORMED** - - .. math:: - - R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y'))}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}} - - -e. **method=CV\_TM\_CCOEFF** - - .. math:: - - R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I(x+x',y+y')) - - where - - .. math:: - - \begin{array}{l} T'(x',y')=T(x',y') - 1/(w \cdot h) \cdot \sum _{x'',y''} T(x'',y'') \\ I'(x+x',y+y')=I(x+x',y+y') - 1/(w \cdot h) \cdot \sum _{x'',y''} I(x+x'',y+y'') \end{array} - - -f. **method=CV\_TM\_CCOEFF\_NORMED** - - .. math:: - - R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} } - - -Code -==== - - -.. container:: enumeratevisibleitemswithsquare - - * **What does this program do?** - - .. container:: enumeratevisibleitemswithsquare - - * Loads an input image and a image patch (*template*) - * Perform a template matching procedure by using the OpenCV function :match_template:`matchTemplate <>` with any of the 6 matching methods described before. The user can choose the method by entering its selection in the Trackbar. - * Normalize the output of the matching procedure - * Localize the location with higher matching probability - * Draw a rectangle around the area corresponding to the highest match - - * **Downloadable code**: - Click `here `_ - - * **Code at glance:** - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - - using namespace std; - using namespace cv; - - /// Global Variables - Mat img; Mat templ; Mat result; - char* image_window = "Source Image"; - char* result_window = "Result window"; - - int match_method; - int max_Trackbar = 5; - - /// Function Headers - void MatchingMethod( int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load image and template - img = imread( argv[1], 1 ); - templ = imread( argv[2], 1 ); - - /// Create windows - namedWindow( image_window, WINDOW_AUTOSIZE ); - namedWindow( result_window, WINDOW_AUTOSIZE ); - - /// Create Trackbar - char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED"; - createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod ); - - MatchingMethod( 0, 0 ); - - waitKey(0); - return 0; - } - - /* - * @function MatchingMethod - * @brief Trackbar callback - */ - void MatchingMethod( int, void* ) - { - /// Source image to display - Mat img_display; - img.copyTo( img_display ); - - /// Create the result matrix - int result_cols = img.cols - templ.cols + 1; - int result_rows = img.rows - templ.rows + 1; - - result.create( result_cols, result_rows, CV_32FC1 ); - - /// Do the Matching and Normalize - matchTemplate( img, templ, result, match_method ); - normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() ); - - /// Localizing the best match with minMaxLoc - double minVal; double maxVal; Point minLoc; Point maxLoc; - Point matchLoc; - - minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() ); - - /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better - if( match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED ) - { matchLoc = minLoc; } - else - { matchLoc = maxLoc; } - - /// Show me what you got - rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); - rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); - - imshow( image_window, img_display ); - imshow( result_window, result ); - - return; - } - -Explanation -=========== - -#. Declare some global variables, such as the image, template and result matrices, as well as the match method and the window names: - - .. code-block:: cpp - - Mat img; Mat templ; Mat result; - char* image_window = "Source Image"; - char* result_window = "Result window"; - - int match_method; - int max_Trackbar = 5; - - -#. Load the source image and template: - - .. code-block:: cpp - - img = imread( argv[1], 1 ); - templ = imread( argv[2], 1 ); - -#. Create the windows to show the results: - - .. code-block:: cpp - - namedWindow( image_window, WINDOW_AUTOSIZE ); - namedWindow( result_window, WINDOW_AUTOSIZE ); - -#. Create the Trackbar to enter the kind of matching method to be used. When a change is detected the callback function **MatchingMethod** is called. - - .. code-block:: cpp - - char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED"; - createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod ); - -#. Wait until user exits the program. - - .. code-block:: cpp - - waitKey(0); - return 0; - -#. Let's check out the callback function. First, it makes a copy of the source image: - - .. code-block:: cpp - - Mat img_display; - img.copyTo( img_display ); - - -#. Next, it creates the result matrix that will store the matching results for each template location. Observe in detail the size of the result matrix (which matches all possible locations for it) - - .. code-block:: cpp - - int result_cols = img.cols - templ.cols + 1; - int result_rows = img.rows - templ.rows + 1; - - result.create( result_cols, result_rows, CV_32FC1 ); - -#. Perform the template matching operation: - - .. code-block:: cpp - - matchTemplate( img, templ, result, match_method ); - - the arguments are naturally the input image **I**, the template **T**, the result **R** and the match_method (given by the Trackbar) - -#. We normalize the results: - - .. code-block:: cpp - - normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() ); - -#. We localize the minimum and maximum values in the result matrix **R** by using :min_max_loc:`minMaxLoc <>`. - - .. code-block:: cpp - - double minVal; double maxVal; Point minLoc; Point maxLoc; - Point matchLoc; - - minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() ); - - the function calls as arguments: - - .. container:: enumeratevisibleitemswithsquare - - + **result:** The source array - + **&minVal** and **&maxVal:** Variables to save the minimum and maximum values in **result** - + **&minLoc** and **&maxLoc:** The Point locations of the minimum and maximum values in the array. - + **Mat():** Optional mask - - -#. For the first two methods ( TM\_SQDIFF and MT\_SQDIFF\_NORMED ) the best match are the lowest values. For all the others, higher values represent better matches. So, we save the corresponding value in the **matchLoc** variable: - - .. code-block:: cpp - - if( match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED ) - { matchLoc = minLoc; } - else - { matchLoc = maxLoc; } - -#. Display the source image and the result matrix. Draw a rectangle around the highest possible matching area: - - .. code-block:: cpp - - rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); - rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 ); - - imshow( image_window, img_display ); - imshow( result_window, result ); - - -Results -======= - -#. Testing our program with an input image such as: - - .. image:: images/Template_Matching_Original_Image.jpg - :align: center - - and a template image: - - .. image:: images/Template_Matching_Template_Image.jpg - :align: center - -#. Generate the following result matrices (first row are the standard methods SQDIFF, CCORR and CCOEFF, second row are the same methods in its normalized version). In the first column, the darkest is the better match, for the other two columns, the brighter a location, the higher the match. - - ============ ============ ============ - |Result_0| |Result_2| |Result_4| - ============ ============ ============ - |Result_1| |Result_3| |Result_5| - ============ ============ ============ - - .. |Result_0| image:: images/Template_Matching_Correl_Result_0.jpg - :align: middle - - .. |Result_1| image:: images/Template_Matching_Correl_Result_1.jpg - :align: middle - - .. |Result_2| image:: images/Template_Matching_Correl_Result_2.jpg - :align: middle - - .. |Result_3| image:: images/Template_Matching_Correl_Result_3.jpg - :align: middle - - .. |Result_4| image:: images/Template_Matching_Correl_Result_4.jpg - :align: middle - - .. |Result_5| image:: images/Template_Matching_Correl_Result_5.jpg - :align: middle - -#. The right match is shown below (black rectangle around the face of the guy at the right). Notice that CCORR and CCDEFF gave erroneous best matches, however their normalized version did it right, this may be due to the fact that we are only considering the "highest match" and not the other possible high matches. - - .. image:: images/Template_Matching_Image_Result.jpg - :align: center diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/Morphology_1_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_1_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/Morphology_1_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/Morphology_2_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/Morphology_2_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/Morphology_2_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/Pyramids_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/Pyramids_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/Pyramids_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/Smoothing_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/Smoothing_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/Smoothing_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/Threshold_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/Threshold_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/Threshold_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Back_Projection_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/histograms/Back_Projection_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Back_Projection_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/histograms/Back_Projection_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Calculation_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/histograms/Histogram_Calculation_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Calculation_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/histograms/Histogram_Calculation_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Comparison_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/histograms/Histogram_Comparison_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Comparison_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/histograms/Histogram_Comparison_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Equalization_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/histograms/Histogram_Equalization_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Histogram_Equalization_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/histograms/Histogram_Equalization_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Template_Matching_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/histograms/Template_Matching_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/histograms/Template_Matching_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/histograms/Template_Matching_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/imgtrans/Canny_Detector_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/imgtrans/Filter_2D_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/imgtrans/Hough_Circle_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/imgtrans/Hough_Lines_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Remap_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/imgtrans/Remap_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Remap_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/imgtrans/Remap_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Warp_Affine_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/imgtrans/Warp_Affine_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/imgtrans/Warp_Affine_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/imgtrans/Warp_Affine_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Bounding_Rects_Circles_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/shapedescriptors/Bounding_Rects_Circles_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Bounding_Rects_Circles_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/shapedescriptors/Bounding_Rects_Circles_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Bounding_Rotated_Ellipses_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/shapedescriptors/Bounding_Rotated_Ellipses_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Bounding_Rotated_Ellipses_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/shapedescriptors/Bounding_Rotated_Ellipses_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Find_Contours_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/shapedescriptors/Find_Contours_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Find_Contours_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/shapedescriptors/Find_Contours_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Hull_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/shapedescriptors/Hull_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Hull_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/shapedescriptors/Hull_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Moments_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/shapedescriptors/Moments_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Moments_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/shapedescriptors/Moments_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Point_Polygon_Test_Tutorial_Cover.jpg b/doc/tutorials/imgproc/images/shapedescriptors/Point_Polygon_Test_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/images/shapedescriptors/Point_Polygon_Test_Tutorial_Cover.jpg rename to doc/tutorials/imgproc/images/shapedescriptors/Point_Polygon_Test_Tutorial_Cover.jpg diff --git a/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.rst b/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.rst deleted file mode 100644 index 11f9b3d8c6..0000000000 --- a/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.rst +++ /dev/null @@ -1,284 +0,0 @@ -.. _canny_detector: - -Canny Edge Detector -******************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :canny:`Canny <>` to implement the Canny Edge Detector. - -Theory -======= - -#. The *Canny Edge detector* was developed by John F. Canny in 1986. Also known to many as the *optimal detector*, Canny algorithm aims to satisfy three main criteria: - - * **Low error rate:** Meaning a good detection of only existent edges. - * **Good localization:** The distance between edge pixels detected and real edge pixels have to be minimized. - * **Minimal response:** Only one detector response per edge. - -Steps ------- - -#. Filter out any noise. The Gaussian filter is used for this purpose. An example of a Gaussian kernel of :math:`size = 5` that might be used is shown below: - - .. math:: - - K = \dfrac{1}{159}\begin{bmatrix} - 2 & 4 & 5 & 4 & 2 \\ - 4 & 9 & 12 & 9 & 4 \\ - 5 & 12 & 15 & 12 & 5 \\ - 4 & 9 & 12 & 9 & 4 \\ - 2 & 4 & 5 & 4 & 2 - \end{bmatrix} - - -#. Find the intensity gradient of the image. For this, we follow a procedure analogous to Sobel: - - a. Apply a pair of convolution masks (in :math:`x` and :math:`y` directions: - - .. math:: - - G_{x} = \begin{bmatrix} - -1 & 0 & +1 \\ - -2 & 0 & +2 \\ - -1 & 0 & +1 - \end{bmatrix} - - G_{y} = \begin{bmatrix} - -1 & -2 & -1 \\ - 0 & 0 & 0 \\ - +1 & +2 & +1 - \end{bmatrix} - - b. Find the gradient strength and direction with: - - .. math:: - \begin{array}{l} - G = \sqrt{ G_{x}^{2} + G_{y}^{2} } \\ - \theta = \arctan(\dfrac{ G_{y} }{ G_{x} }) - \end{array} - - The direction is rounded to one of four possible angles (namely 0, 45, 90 or 135) - -#. *Non-maximum* suppression is applied. This removes pixels that are not considered to be part of an edge. Hence, only thin lines (candidate edges) will remain. - -#. *Hysteresis*: The final step. Canny does use two thresholds (upper and lower): - - a. If a pixel gradient is higher than the *upper* threshold, the pixel is accepted as an edge - b. If a pixel gradient value is below the *lower* threshold, then it is rejected. - c. If the pixel gradient is between the two thresholds, then it will be accepted only if it is connected to a pixel that is above the *upper* threshold. - - Canny recommended a *upper*:*lower* ratio between 2:1 and 3:1. - -#. For more details, you can always consult your favorite Computer Vision book. - -Code -===== - -#. **What does this program do?** - - * Asks the user to enter a numerical value to set the lower threshold for our *Canny Edge Detector* (by means of a Trackbar) - * Applies the *Canny Detector* and generates a **mask** (bright lines representing the edges on a black background). - * Applies the mask obtained on the original image and display it in a window. - -#. The tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - #include - #include - - using namespace cv; - - /// Global variables - - Mat src, src_gray; - Mat dst, detected_edges; - - int edgeThresh = 1; - int lowThreshold; - int const max_lowThreshold = 100; - int ratio = 3; - int kernel_size = 3; - char* window_name = "Edge Map"; - - /* - * @function CannyThreshold - * @brief Trackbar callback - Canny thresholds input with a ratio 1:3 - */ - void CannyThreshold(int, void*) - { - /// Reduce noise with a kernel 3x3 - blur( src_gray, detected_edges, Size(3,3) ); - - /// Canny detector - Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size ); - - /// Using Canny's output as a mask, we display our result - dst = Scalar::all(0); - - src.copyTo( dst, detected_edges); - imshow( window_name, dst ); - } - - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load an image - src = imread( argv[1] ); - - if( !src.data ) - { return -1; } - - /// Create a matrix of the same type and size as src (for dst) - dst.create( src.size(), src.type() ); - - /// Convert the image to grayscale - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - - /// Create a window - namedWindow( window_name, WINDOW_AUTOSIZE ); - - /// Create a Trackbar for user to enter threshold - createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold ); - - /// Show the image - CannyThreshold(0, 0); - - /// Wait until user exit program by pressing a key - waitKey(0); - - return 0; - } - -Explanation -============ - -#. Create some needed variables: - - .. code-block:: cpp - - Mat src, src_gray; - Mat dst, detected_edges; - - int edgeThresh = 1; - int lowThreshold; - int const max_lowThreshold = 100; - int ratio = 3; - int kernel_size = 3; - char* window_name = "Edge Map"; - - Note the following: - - a. We establish a ratio of lower:upper threshold of 3:1 (with the variable *ratio*) - b. We set the kernel size of :math:`3` (for the Sobel operations to be performed internally by the Canny function) - c. We set a maximum value for the lower Threshold of :math:`100`. - - -#. Loads the source image: - - .. code-block:: cpp - - /// Load an image - src = imread( argv[1] ); - - if( !src.data ) - { return -1; } - -#. Create a matrix of the same type and size of *src* (to be *dst*) - - .. code-block:: cpp - - dst.create( src.size(), src.type() ); - -#. Convert the image to grayscale (using the function :cvt_color:`cvtColor <>`: - - .. code-block:: cpp - - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - -#. Create a window to display the results - - .. code-block:: cpp - - namedWindow( window_name, WINDOW_AUTOSIZE ); - -#. Create a Trackbar for the user to enter the lower threshold for our Canny detector: - - .. code-block:: cpp - - createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold ); - - Observe the following: - - a. The variable to be controlled by the Trackbar is *lowThreshold* with a limit of *max_lowThreshold* (which we set to 100 previously) - b. Each time the Trackbar registers an action, the callback function *CannyThreshold* will be invoked. - -#. Let's check the *CannyThreshold* function, step by step: - - a. First, we blur the image with a filter of kernel size 3: - - .. code-block:: cpp - - blur( src_gray, detected_edges, Size(3,3) ); - - b. Second, we apply the OpenCV function :canny:`Canny <>`: - - .. code-block:: cpp - - Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size ); - - where the arguments are: - - * *detected_edges*: Source image, grayscale - * *detected_edges*: Output of the detector (can be the same as the input) - * *lowThreshold*: The value entered by the user moving the Trackbar - * *highThreshold*: Set in the program as three times the lower threshold (following Canny's recommendation) - * *kernel_size*: We defined it to be 3 (the size of the Sobel kernel to be used internally) - -#. We fill a *dst* image with zeros (meaning the image is completely black). - - .. code-block:: cpp - - dst = Scalar::all(0); - -#. Finally, we will use the function :copy_to:`copyTo <>` to map only the areas of the image that are identified as edges (on a black background). - - .. code-block:: cpp - - src.copyTo( dst, detected_edges); - - :copy_to:`copyTo <>` copy the *src* image onto *dst*. However, it will only copy the pixels in the locations where they have non-zero values. Since the output of the Canny detector is the edge contours on a black background, the resulting *dst* will be black in all the area but the detected edges. - -#. We display our result: - - .. code-block:: cpp - - imshow( window_name, dst ); - -Result -======= - -* After compiling the code above, we can run it giving as argument the path to an image. For example, using as an input the following image: - - .. image:: images/Canny_Detector_Tutorial_Original_Image.jpg - :alt: Original test image - :width: 200pt - :align: center - -* Moving the slider, trying different threshold, we obtain the following result: - - .. image:: images/Canny_Detector_Tutorial_Result.jpg - :alt: Result after running Canny - :width: 200pt - :align: center - -* Notice how the image is superposed to the black background on the edge regions. diff --git a/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.rst b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.rst deleted file mode 100644 index 6239d787e8..0000000000 --- a/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.rst +++ /dev/null @@ -1,226 +0,0 @@ -.. _copyMakeBorderTutorial: - -Adding borders to your images -****************************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :copy_make_border:`copyMakeBorder <>` to set the borders (extra padding to your image). - -Theory -======== - -.. note:: - The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. - - -#. In our previous tutorial we learned to use convolution to operate on images. One problem that naturally arises is how to handle the boundaries. How can we convolve them if the evaluated points are at the edge of the image? - -#. What most of OpenCV functions do is to copy a given image onto another slightly larger image and then automatically pads the boundary (by any of the methods explained in the sample code just below). This way, the convolution can be performed over the needed pixels without problems (the extra padding is cut after the operation is done). - -#. In this tutorial, we will briefly explore two ways of defining the extra padding (border) for an image: - - a. **BORDER_CONSTANT**: Pad the image with a constant value (i.e. black or :math:`0` - - b. **BORDER_REPLICATE**: The row or column at the very edge of the original is replicated to the extra border. - - This will be seen more clearly in the Code section. - - - -Code -====== - -#. **What does this program do?** - - * Load an image - * Let the user choose what kind of padding use in the input image. There are two options: - - #. *Constant value border*: Applies a padding of a constant value for the whole border. This value will be updated randomly each 0.5 seconds. - #. *Replicated border*: The border will be replicated from the pixel values at the edges of the original image. - - The user chooses either option by pressing 'c' (constant) or 'r' (replicate) - * The program finishes when the user presses 'ESC' - -#. The tutorial code's is shown lines below. You can also download it from `here `_ - - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - #include - #include - - using namespace cv; - - /// Global Variables - Mat src, dst; - int top, bottom, left, right; - int borderType; - Scalar value; - char* window_name = "copyMakeBorder Demo"; - RNG rng(12345); - - /* @function main */ - int main( int argc, char** argv ) - { - - int c; - - /// Load an image - src = imread( argv[1] ); - - if( !src.data ) - { return -1; - printf(" No data entered, please enter the path to an image file \n"); - } - - /// Brief how-to for this program - printf( "\n \t copyMakeBorder Demo: \n" ); - printf( "\t -------------------- \n" ); - printf( " ** Press 'c' to set the border to a random constant value \n"); - printf( " ** Press 'r' to set the border to be replicated \n"); - printf( " ** Press 'ESC' to exit the program \n"); - - /// Create window - namedWindow( window_name, WINDOW_AUTOSIZE ); - - /// Initialize arguments for the filter - top = (int) (0.05*src.rows); bottom = (int) (0.05*src.rows); - left = (int) (0.05*src.cols); right = (int) (0.05*src.cols); - dst = src; - - imshow( window_name, dst ); - - while( true ) - { - c = waitKey(500); - - if( (char)c == 27 ) - { break; } - else if( (char)c == 'c' ) - { borderType = BORDER_CONSTANT; } - else if( (char)c == 'r' ) - { borderType = BORDER_REPLICATE; } - - value = Scalar( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) ); - copyMakeBorder( src, dst, top, bottom, left, right, borderType, value ); - - imshow( window_name, dst ); - } - - return 0; - } - - -Explanation -============= - -#. First we declare the variables we are going to use: - - .. code-block:: cpp - - Mat src, dst; - int top, bottom, left, right; - int borderType; - Scalar value; - char* window_name = "copyMakeBorder Demo"; - RNG rng(12345); - - Especial attention deserves the variable *rng* which is a random number generator. We use it to generate the random border color, as we will see soon. - -#. As usual we load our source image *src*: - - .. code-block:: cpp - - src = imread( argv[1] ); - - if( !src.data ) - { return -1; - printf(" No data entered, please enter the path to an image file \n"); - } - -#. After giving a short intro of how to use the program, we create a window: - - .. code-block:: cpp - - namedWindow( window_name, WINDOW_AUTOSIZE ); - -#. Now we initialize the argument that defines the size of the borders (*top*, *bottom*, *left* and *right*). We give them a value of 5% the size of *src*. - - .. code-block:: cpp - - top = (int) (0.05*src.rows); bottom = (int) (0.05*src.rows); - left = (int) (0.05*src.cols); right = (int) (0.05*src.cols); - -#. The program begins a *while* loop. If the user presses 'c' or 'r', the *borderType* variable takes the value of *BORDER_CONSTANT* or *BORDER_REPLICATE* respectively: - - .. code-block:: cpp - - while( true ) - { - c = waitKey(500); - - if( (char)c == 27 ) - { break; } - else if( (char)c == 'c' ) - { borderType = BORDER_CONSTANT; } - else if( (char)c == 'r' ) - { borderType = BORDER_REPLICATE; } - -#. In each iteration (after 0.5 seconds), the variable *value* is updated... - - .. code-block:: cpp - - value = Scalar( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) ); - - with a random value generated by the **RNG** variable *rng*. This value is a number picked randomly in the range :math:`[0,255]` - -#. Finally, we call the function :copy_make_border:`copyMakeBorder <>` to apply the respective padding: - - .. code-block:: cpp - - copyMakeBorder( src, dst, top, bottom, left, right, borderType, value ); - - The arguments are: - - a. *src*: Source image - #. *dst*: Destination image - #. *top*, *bottom*, *left*, *right*: Length in pixels of the borders at each side of the image. We define them as being 5% of the original size of the image. - #. *borderType*: Define what type of border is applied. It can be constant or replicate for this example. - #. *value*: If *borderType* is *BORDER_CONSTANT*, this is the value used to fill the border pixels. - -#. We display our output image in the image created previously - - .. code-block:: cpp - - imshow( window_name, dst ); - - - - -Results -======== - -#. After compiling the code above, you can execute it giving as argument the path of an image. The result should be: - - .. container:: enumeratevisibleitemswithsquare - - * By default, it begins with the border set to BORDER_CONSTANT. Hence, a succession of random colored borders will be shown. - * If you press 'r', the border will become a replica of the edge pixels. - * If you press 'c', the random colored borders will appear again - * If you press 'ESC' the program will exit. - - Below some screenshot showing how the border changes color and how the *BORDER_REPLICATE* option looks: - - - .. image:: images/CopyMakeBorder_Tutorial_Results.jpg - :alt: Final result after copyMakeBorder application - :width: 750pt - :align: center diff --git a/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.rst b/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.rst deleted file mode 100644 index 0548c5b501..0000000000 --- a/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.rst +++ /dev/null @@ -1,201 +0,0 @@ -.. _filter_2d: - -Making your own linear filters! -******************************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :filter2d:`filter2D <>` to create your own linear filters. - -Theory -======= - -.. note:: - The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. - - -Convolution ------------- -In a very general sense, convolution is an operation between every part of an image and an operator (kernel). - -What is a kernel? ------------------- -A kernel is essentially a fixed size array of numerical coefficeints along with an *anchor point* in that array, which is tipically located at the center. - -.. image:: images/filter_2d_tutorial_kernel_theory.png - :alt: kernel example - :align: center - -How does convolution with a kernel work? ------------------------------------------ - -Assume you want to know the resulting value of a particular location in the image. The value of the convolution is calculated in the following way: - -#. Place the kernel anchor on top of a determined pixel, with the rest of the kernel overlaying the corresponding local pixels in the image. - -#. Multiply the kernel coefficients by the corresponding image pixel values and sum the result. - -#. Place the result to the location of the *anchor* in the input image. - -#. Repeat the process for all pixels by scanning the kernel over the entire image. - -Expressing the procedure above in the form of an equation we would have: - -.. math:: - - H(x,y) = \sum_{i=0}^{M_{i} - 1} \sum_{j=0}^{M_{j}-1} I(x+i - a_{i}, y + j - a_{j})K(i,j) - -Fortunately, OpenCV provides you with the function :filter2d:`filter2D <>` so you do not have to code all these operations. - -Code -====== - -#. **What does this program do?** - - * Loads an image - * Performs a *normalized box filter*. For instance, for a kernel of size :math:`size = 3`, the kernel would be: - - .. math:: - - K = \dfrac{1}{3 \cdot 3} \begin{bmatrix} - 1 & 1 & 1 \\ - 1 & 1 & 1 \\ - 1 & 1 & 1 - \end{bmatrix} - - The program will perform the filter operation with kernels of sizes 3, 5, 7, 9 and 11. - - * The filter output (with each kernel) will be shown during 500 milliseconds - -#. The tutorial code's is shown lines below. You can also download it from `here `_ - - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - #include - #include - - using namespace cv; - - /* @function main */ - int main ( int argc, char** argv ) - { - /// Declare variables - Mat src, dst; - - Mat kernel; - Point anchor; - double delta; - int ddepth; - int kernel_size; - char* window_name = "filter2D Demo"; - - int c; - - /// Load an image - src = imread( argv[1] ); - - if( !src.data ) - { return -1; } - - /// Create window - namedWindow( window_name, WINDOW_AUTOSIZE ); - - /// Initialize arguments for the filter - anchor = Point( -1, -1 ); - delta = 0; - ddepth = -1; - - /// Loop - Will filter the image with different kernel sizes each 0.5 seconds - int ind = 0; - while( true ) - { - c = waitKey(500); - /// Press 'ESC' to exit the program - if( (char)c == 27 ) - { break; } - - /// Update kernel size for a normalized box filter - kernel_size = 3 + 2*( ind%5 ); - kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size); - - /// Apply filter - filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT ); - imshow( window_name, dst ); - ind++; - } - - return 0; - } - -Explanation -============= - -#. Load an image - - .. code-block:: cpp - - src = imread( argv[1] ); - - if( !src.data ) - { return -1; } - -#. Create a window to display the result - - .. code-block:: cpp - - namedWindow( window_name, WINDOW_AUTOSIZE ); - -#. Initialize the arguments for the linear filter - - .. code-block:: cpp - - anchor = Point( -1, -1 ); - delta = 0; - ddepth = -1; - - -#. Perform an infinite loop updating the kernel size and applying our linear filter to the input image. Let's analyze that more in detail: - -#. First we define the kernel our filter is going to use. Here it is: - - .. code-block:: cpp - - kernel_size = 3 + 2*( ind%5 ); - kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size); - - The first line is to update the *kernel_size* to odd values in the range: :math:`[3,11]`. The second line actually builds the kernel by setting its value to a matrix filled with :math:`1's` and normalizing it by dividing it between the number of elements. - -#. After setting the kernel, we can generate the filter by using the function :filter2d:`filter2D <>`: - - .. code-block:: cpp - - filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT ); - - The arguments denote: - - a. *src*: Source image - #. *dst*: Destination image - #. *ddepth*: The depth of *dst*. A negative value (such as :math:`-1`) indicates that the depth is the same as the source. - #. *kernel*: The kernel to be scanned through the image - #. *anchor*: The position of the anchor relative to its kernel. The location *Point(-1, -1)* indicates the center by default. - #. *delta*: A value to be added to each pixel during the convolution. By default it is :math:`0` - #. *BORDER_DEFAULT*: We let this value by default (more details in the following tutorial) - -#. Our program will effectuate a *while* loop, each 500 ms the kernel size of our filter will be updated in the range indicated. - -Results -======== - -#. After compiling the code above, you can execute it giving as argument the path of an image. The result should be a window that shows an image blurred by a normalized filter. Each 0.5 seconds the kernel size should change, as can be seen in the series of snapshots below: - - .. image:: images/filter_2d_tutorial_result.jpg - :alt: kernel example - :align: center diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst deleted file mode 100644 index 8ca7992260..0000000000 --- a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.rst +++ /dev/null @@ -1,182 +0,0 @@ -.. _hough_circle: - -Hough Circle Transform -*********************** - -Goal -===== -In this tutorial you will learn how to: - -* Use the OpenCV function :hough_circles:`HoughCircles <>` to detect circles in an image. - -Theory -======= - -Hough Circle Transform ------------------------- - -* The Hough Circle Transform works in a *roughly* analogous way to the Hough Line Transform explained in the previous tutorial. -* In the line detection case, a line was defined by two parameters :math:`(r, \theta)`. In the circle case, we need three parameters to define a circle: - - .. math:: - - C : ( x_{center}, y_{center}, r ) - - where :math:`(x_{center}, y_{center})` define the center position (green point) and :math:`r` is the radius, which allows us to completely define a circle, as it can be seen below: - - .. image:: images/Hough_Circle_Tutorial_Theory_0.jpg - :alt: Result of detecting circles with Hough Transform - :align: center - -* For sake of efficiency, OpenCV implements a detection method slightly trickier than the standard Hough Transform: *The Hough gradient method*, which is made up of two main stages. The first stage involves edge detection and finding the possible circle centers and the second stage finds the best radius for each candidate center. For more details, please check the book *Learning OpenCV* or your favorite Computer Vision bibliography - -Code -====== - -#. **What does this program do?** - - * Loads an image and blur it to reduce the noise - * Applies the *Hough Circle Transform* to the blurred image . - * Display the detected circle in a window. - - .. |TutorialHoughCirclesSimpleDownload| replace:: here - .. _TutorialHoughCirclesSimpleDownload: https://github.com/Itseez/opencv/tree/master/samples/cpp/houghcircles.cpp - .. |TutorialHoughCirclesFancyDownload| replace:: here - .. _TutorialHoughCirclesFancyDownload: https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp - -#. The sample code that we will explain can be downloaded from |TutorialHoughCirclesSimpleDownload|_. A slightly fancier version (which shows trackbars for changing the threshold values) can be found |TutorialHoughCirclesFancyDownload|_. - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - - using namespace cv; - - /* @function main */ - int main(int argc, char** argv) - { - Mat src, src_gray; - - /// Read the image - src = imread( argv[1], 1 ); - - if( !src.data ) - { return -1; } - - /// Convert it to gray - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - - /// Reduce the noise so we avoid false circle detection - GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 ); - - vector circles; - - /// Apply the Hough Transform to find the circles - HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 ); - - /// Draw the circles detected - for( size_t i = 0; i < circles.size(); i++ ) - { - Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); - int radius = cvRound(circles[i][2]); - // circle center - circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 ); - // circle outline - circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 ); - } - - /// Show your results - namedWindow( "Hough Circle Transform Demo", WINDOW_AUTOSIZE ); - imshow( "Hough Circle Transform Demo", src ); - - waitKey(0); - return 0; - } - - -Explanation -============ - - -#. Load an image - - .. code-block:: cpp - - src = imread( argv[1], 1 ); - - if( !src.data ) - { return -1; } - -#. Convert it to grayscale: - - .. code-block:: cpp - - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - -#. Apply a Gaussian blur to reduce noise and avoid false circle detection: - - .. code-block:: cpp - - GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 ); - -#. Proceed to apply Hough Circle Transform: - - .. code-block:: cpp - - vector circles; - - HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 ); - - with the arguments: - - * *src_gray*: Input image (grayscale). - * *circles*: A vector that stores sets of 3 values: :math:`x_{c}, y_{c}, r` for each detected circle. - * *HOUGH_GRADIENT*: Define the detection method. Currently this is the only one available in OpenCV. - * *dp = 1*: The inverse ratio of resolution. - * *min_dist = src_gray.rows/8*: Minimum distance between detected centers. - * *param_1 = 200*: Upper threshold for the internal Canny edge detector. - * *param_2* = 100*: Threshold for center detection. - * *min_radius = 0*: Minimum radio to be detected. If unknown, put zero as default. - * *max_radius = 0*: Maximum radius to be detected. If unknown, put zero as default. - -#. Draw the detected circles: - - .. code-block:: cpp - - for( size_t i = 0; i < circles.size(); i++ ) - { - Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); - int radius = cvRound(circles[i][2]); - // circle center - circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 ); - // circle outline - circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 ); - } - - You can see that we will draw the circle(s) on red and the center(s) with a small green dot - -#. Display the detected circle(s): - - .. code-block:: cpp - - namedWindow( "Hough Circle Transform Demo", WINDOW_AUTOSIZE ); - imshow( "Hough Circle Transform Demo", src ); - -#. Wait for the user to exit the program - - .. code-block:: cpp - - waitKey(0); - - -Result -======= - -The result of running the code above with a test image is shown below: - -.. image:: images/Hough_Circle_Tutorial_Result.jpg - :alt: Result of detecting circles with Hough Transform - :align: center diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.rst b/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.rst deleted file mode 100644 index 52602d8d55..0000000000 --- a/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.rst +++ /dev/null @@ -1,292 +0,0 @@ -.. _hough_lines: - -Hough Line Transform -********************* - -Goal -===== - -In this tutorial you will learn how to: - -* Use the OpenCV functions :hough_lines:`HoughLines <>` and :hough_lines_p:`HoughLinesP <>` to detect lines in an image. - -Theory -======= - -.. note:: - The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. - -Hough Line Transform ---------------------- -#. The Hough Line Transform is a transform used to detect straight lines. -#. To apply the Transform, first an edge detection pre-processing is desirable. - -How does it work? -^^^^^^^^^^^^^^^^^^ - -#. As you know, a line in the image space can be expressed with two variables. For example: - - a. In the **Cartesian coordinate system:** Parameters: :math:`(m,b)`. - b. In the **Polar coordinate system:** Parameters: :math:`(r,\theta)` - - .. image:: images/Hough_Lines_Tutorial_Theory_0.jpg - :alt: Line variables - :align: center - - For Hough Transforms, we will express lines in the *Polar system*. Hence, a line equation can be written as: - - .. math:: - - y = \left ( -\dfrac{\cos \theta}{\sin \theta} \right ) x + \left ( \dfrac{r}{\sin \theta} \right ) - - Arranging the terms: :math:`r = x \cos \theta + y \sin \theta` - -#. In general for each point :math:`(x_{0}, y_{0})`, we can define the family of lines that goes through that point as: - - .. math:: - - r_{\theta} = x_{0} \cdot \cos \theta + y_{0} \cdot \sin \theta - - Meaning that each pair :math:`(r_{\theta},\theta)` represents each line that passes by :math:`(x_{0}, y_{0})`. - -#. If for a given :math:`(x_{0}, y_{0})` we plot the family of lines that goes through it, we get a sinusoid. For instance, for :math:`x_{0} = 8` and :math:`y_{0} = 6` we get the following plot (in a plane :math:`\theta` - :math:`r`): - - .. image:: images/Hough_Lines_Tutorial_Theory_1.jpg - :alt: Polar plot of a the family of lines of a point - :align: center - - We consider only points such that :math:`r > 0` and :math:`0< \theta < 2 \pi`. - -#. We can do the same operation above for all the points in an image. If the curves of two different points intersect in the plane :math:`\theta` - :math:`r`, that means that both points belong to a same line. For instance, following with the example above and drawing the plot for two more points: :math:`x_{1} = 9`, :math:`y_{1} = 4` and :math:`x_{2} = 12`, :math:`y_{2} = 3`, we get: - - .. image:: images/Hough_Lines_Tutorial_Theory_2.jpg - :alt: Polar plot of the family of lines for three points - :align: center - - The three plots intersect in one single point :math:`(0.925, 9.6)`, these coordinates are the parameters (:math:`\theta, r`) or the line in which :math:`(x_{0}, y_{0})`, :math:`(x_{1}, y_{1})` and :math:`(x_{2}, y_{2})` lay. - -#. What does all the stuff above mean? It means that in general, a line can be *detected* by finding the number of intersections between curves.The more curves intersecting means that the line represented by that intersection have more points. In general, we can define a *threshold* of the minimum number of intersections needed to *detect* a line. - -#. This is what the Hough Line Transform does. It keeps track of the intersection between curves of every point in the image. If the number of intersections is above some *threshold*, then it declares it as a line with the parameters :math:`(\theta, r_{\theta})` of the intersection point. - -Standard and Probabilistic Hough Line Transform -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -OpenCV implements two kind of Hough Line Transforms: - -a. **The Standard Hough Transform** - - * It consists in pretty much what we just explained in the previous section. It gives you as result a vector of couples :math:`(\theta, r_{\theta})` - - * In OpenCV it is implemented with the function :hough_lines:`HoughLines <>` - -b. **The Probabilistic Hough Line Transform** - - * A more efficient implementation of the Hough Line Transform. It gives as output the extremes of the detected lines :math:`(x_{0}, y_{0}, x_{1}, y_{1})` - - * In OpenCV it is implemented with the function :hough_lines_p:`HoughLinesP <>` - -Code -====== - -.. |TutorialHoughLinesSimpleDownload| replace:: here -.. _TutorialHoughLinesSimpleDownload: https://github.com/Itseez/opencv/tree/master/samples/cpp/houghlines.cpp -.. |TutorialHoughLinesFancyDownload| replace:: here -.. _TutorialHoughLinesFancyDownload: https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp - - -#. **What does this program do?** - - * Loads an image - * Applies either a *Standard Hough Line Transform* or a *Probabilistic Line Transform*. - * Display the original image and the detected line in two windows. - -#. The sample code that we will explain can be downloaded from |TutorialHoughLinesSimpleDownload|_. A slightly fancier version (which shows both Hough standard and probabilistic with trackbars for changing the threshold values) can be found |TutorialHoughLinesFancyDownload|_. - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - - #include - - using namespace cv; - using namespace std; - - void help() - { - cout << "\nThis program demonstrates line finding with the Hough transform.\n" - "Usage:\n" - "./houghlines , Default is pic1.jpg\n" << endl; - } - - int main(int argc, char** argv) - { - const char* filename = argc >= 2 ? argv[1] : "pic1.jpg"; - - Mat src = imread(filename, 0); - if(src.empty()) - { - help(); - cout << "can not open " << filename << endl; - return -1; - } - - Mat dst, cdst; - Canny(src, dst, 50, 200, 3); - cvtColor(dst, cdst, COLOR_GRAY2BGR); - - #if 0 - vector lines; - HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 ); - - for( size_t i = 0; i < lines.size(); i++ ) - { - float rho = lines[i][0], theta = lines[i][1]; - Point pt1, pt2; - double a = cos(theta), b = sin(theta); - double x0 = a*rho, y0 = b*rho; - pt1.x = cvRound(x0 + 1000*(-b)); - pt1.y = cvRound(y0 + 1000*(a)); - pt2.x = cvRound(x0 - 1000*(-b)); - pt2.y = cvRound(y0 - 1000*(a)); - line( cdst, pt1, pt2, Scalar(0,0,255), 3, LINE_AA); - } - #else - vector lines; - HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 ); - for( size_t i = 0; i < lines.size(); i++ ) - { - Vec4i l = lines[i]; - line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA); - } - #endif - imshow("source", src); - imshow("detected lines", cdst); - - waitKey(); - - return 0; - } - -Explanation -============= - -#. Load an image - - .. code-block:: cpp - - Mat src = imread(filename, 0); - if(src.empty()) - { - help(); - cout << "can not open " << filename << endl; - return -1; - } - -#. Detect the edges of the image by using a Canny detector - - .. code-block:: cpp - - Canny(src, dst, 50, 200, 3); - - Now we will apply the Hough Line Transform. We will explain how to use both OpenCV functions available for this purpose: - -#. **Standard Hough Line Transform** - - a. First, you apply the Transform: - - .. code-block:: cpp - - vector lines; - HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 ); - - with the following arguments: - - * *dst*: Output of the edge detector. It should be a grayscale image (although in fact it is a binary one) - * *lines*: A vector that will store the parameters :math:`(r,\theta)` of the detected lines - * *rho* : The resolution of the parameter :math:`r` in pixels. We use **1** pixel. - * *theta*: The resolution of the parameter :math:`\theta` in radians. We use **1 degree** (CV_PI/180) - * *threshold*: The minimum number of intersections to "*detect*" a line - * *srn* and *stn*: Default parameters to zero. Check OpenCV reference for more info. - - b. And then you display the result by drawing the lines. - - .. code-block:: cpp - - for( size_t i = 0; i < lines.size(); i++ ) - { - float rho = lines[i][0], theta = lines[i][1]; - Point pt1, pt2; - double a = cos(theta), b = sin(theta); - double x0 = a*rho, y0 = b*rho; - pt1.x = cvRound(x0 + 1000*(-b)); - pt1.y = cvRound(y0 + 1000*(a)); - pt2.x = cvRound(x0 - 1000*(-b)); - pt2.y = cvRound(y0 - 1000*(a)); - line( cdst, pt1, pt2, Scalar(0,0,255), 3, LINE_AA); - } - -#. **Probabilistic Hough Line Transform** - - a. First you apply the transform: - - .. code-block:: cpp - - vector lines; - HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 ); - - with the arguments: - - * *dst*: Output of the edge detector. It should be a grayscale image (although in fact it is a binary one) - * *lines*: A vector that will store the parameters :math:`(x_{start}, y_{start}, x_{end}, y_{end})` of the detected lines - * *rho* : The resolution of the parameter :math:`r` in pixels. We use **1** pixel. - * *theta*: The resolution of the parameter :math:`\theta` in radians. We use **1 degree** (CV_PI/180) - * *threshold*: The minimum number of intersections to "*detect*" a line - * *minLinLength*: The minimum number of points that can form a line. Lines with less than this number of points are disregarded. - * *maxLineGap*: The maximum gap between two points to be considered in the same line. - - b. And then you display the result by drawing the lines. - - .. code-block:: cpp - - for( size_t i = 0; i < lines.size(); i++ ) - { - Vec4i l = lines[i]; - line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, LINE_AA); - } - - -#. Display the original image and the detected lines: - - .. code-block:: cpp - - imshow("source", src); - imshow("detected lines", cdst); - -#. Wait until the user exits the program - - .. code-block:: cpp - - waitKey(); - - -Result -======= - -.. note:: - - The results below are obtained using the slightly fancier version we mentioned in the *Code* section. It still implements the same stuff as above, only adding the Trackbar for the Threshold. - -Using an input image such as: - -.. image:: images/Hough_Lines_Tutorial_Original_Image.jpg - :alt: Result of detecting lines with Hough Transform - :align: center - -We get the following result by using the Probabilistic Hough Line Transform: - -.. image:: images/Hough_Lines_Tutorial_Result.jpg - :alt: Result of detecting lines with Hough Transform - :align: center - -You may observe that the number of lines detected vary while you change the *threshold*. The explanation is sort of evident: If you establish a higher threshold, fewer lines will be detected (since you will need more points to declare a line detected). diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.rst b/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.rst deleted file mode 100644 index 911fe6b6f6..0000000000 --- a/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.rst +++ /dev/null @@ -1,188 +0,0 @@ -.. _laplace_operator: - -Laplace Operator -***************** - -Goal -===== - - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :laplacian:`Laplacian <>` to implement a discrete analog of the *Laplacian operator*. - - -Theory -======= - -#. In the previous tutorial we learned how to use the *Sobel Operator*. It was based on the fact that in the edge area, the pixel intensity shows a "jump" or a high variation of intensity. Getting the first derivative of the intensity, we observed that an edge is characterized by a maximum, as it can be seen in the figure: - - .. image:: images/Laplace_Operator_Tutorial_Theory_Previous.jpg - :alt: Previous theory - :align: center - -#. And...what happens if we take the second derivative? - - .. image:: images/Laplace_Operator_Tutorial_Theory_ddIntensity.jpg - :alt: Second derivative - :align: center - - You can observe that the second derivative is zero! So, we can also use this criterion to attempt to detect edges in an image. However, note that zeros will not only appear in edges (they can actually appear in other meaningless locations); this can be solved by applying filtering where needed. - - -Laplacian Operator -------------------- - -#. From the explanation above, we deduce that the second derivative can be used to *detect edges*. Since images are "*2D*", we would need to take the derivative in both dimensions. Here, the Laplacian operator comes handy. - -#. The *Laplacian operator* is defined by: - - .. math:: - - Laplace(f) = \dfrac{\partial^{2} f}{\partial x^{2}} + \dfrac{\partial^{2} f}{\partial y^{2}} - -#. The Laplacian operator is implemented in OpenCV by the function :laplacian:`Laplacian <>`. In fact, since the Laplacian uses the gradient of images, it calls internally the *Sobel* operator to perform its computation. - -Code -====== - -#. **What does this program do?** - - * Loads an image - * Remove noise by applying a Gaussian blur and then convert the original image to grayscale - * Applies a Laplacian operator to the grayscale image and stores the output image - * Display the result in a window - -#. The tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - #include - #include - - using namespace cv; - - /* @function main */ - int main( int argc, char** argv ) - { - Mat src, src_gray, dst; - int kernel_size = 3; - int scale = 1; - int delta = 0; - int ddepth = CV_16S; - char* window_name = "Laplace Demo"; - - int c; - - /// Load an image - src = imread( argv[1] ); - - if( !src.data ) - { return -1; } - - /// Remove noise by blurring with a Gaussian filter - GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); - - /// Convert the image to grayscale - cvtColor( src, src_gray, COLOR_RGB2GRAY ); - - /// Create window - namedWindow( window_name, WINDOW_AUTOSIZE ); - - /// Apply Laplace function - Mat abs_dst; - - Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT ); - convertScaleAbs( dst, abs_dst ); - - /// Show what you got - imshow( window_name, abs_dst ); - - waitKey(0); - - return 0; - } - - -Explanation -============ - -#. Create some needed variables: - - .. code-block:: cpp - - Mat src, src_gray, dst; - int kernel_size = 3; - int scale = 1; - int delta = 0; - int ddepth = CV_16S; - char* window_name = "Laplace Demo"; - -#. Loads the source image: - - .. code-block:: cpp - - src = imread( argv[1] ); - - if( !src.data ) - { return -1; } - -#. Apply a Gaussian blur to reduce noise: - - .. code-block:: cpp - - GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); - -#. Convert the image to grayscale using :cvt_color:`cvtColor <>` - - .. code-block:: cpp - - cvtColor( src, src_gray, COLOR_RGB2GRAY ); - -#. Apply the Laplacian operator to the grayscale image: - - .. code-block:: cpp - - Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT ); - - where the arguments are: - - * *src_gray*: The input image. - * *dst*: Destination (output) image - * *ddepth*: Depth of the destination image. Since our input is *CV_8U* we define *ddepth* = *CV_16S* to avoid overflow - * *kernel_size*: The kernel size of the Sobel operator to be applied internally. We use 3 in this example. - * *scale*, *delta* and *BORDER_DEFAULT*: We leave them as default values. - -#. Convert the output from the Laplacian operator to a *CV_8U* image: - - .. code-block:: cpp - - convertScaleAbs( dst, abs_dst ); - -#. Display the result in a window: - - .. code-block:: cpp - - imshow( window_name, abs_dst ); - - -Results -======== - -#. After compiling the code above, we can run it giving as argument the path to an image. For example, using as an input: - - .. image:: images/Laplace_Operator_Tutorial_Original_Image.jpg - :alt: Original test image - :width: 250pt - :align: center - -#. We obtain the following result. Notice how the trees and the silhouette of the cow are approximately well defined (except in areas in which the intensity are very similar, i.e. around the cow's head). Also, note that the roof of the house behind the trees (right side) is notoriously marked. This is due to the fact that the contrast is higher in that region. - - .. image:: images/Laplace_Operator_Tutorial_Result.jpg - :alt: Original test image - :width: 250pt - :align: center diff --git a/doc/tutorials/imgproc/imgtrans/remap/remap.rst b/doc/tutorials/imgproc/imgtrans/remap/remap.rst deleted file mode 100644 index 9f5299cae2..0000000000 --- a/doc/tutorials/imgproc/imgtrans/remap/remap.rst +++ /dev/null @@ -1,313 +0,0 @@ -.. _remap: - -Remapping -********* - -Goal -==== - -In this tutorial you will learn how to: - -a. Use the OpenCV function :remap:`remap <>` to implement simple remapping routines. - -Theory -====== - -What is remapping? ------------------- - -* It is the process of taking pixels from one place in the image and locating them in another position in a new image. - -* To accomplish the mapping process, it might be necessary to do some interpolation for non-integer pixel locations, since there will not always be a one-to-one-pixel correspondence between source and destination images. - -* We can express the remap for every pixel location :math:`(x,y)` as: - - .. math:: - - g(x,y) = f ( h(x,y) ) - - where :math:`g()` is the remapped image, :math:`f()` the source image and :math:`h(x,y)` is the mapping function that operates on :math:`(x,y)`. - -* Let's think in a quick example. Imagine that we have an image :math:`I` and, say, we want to do a remap such that: - - .. math:: - - h(x,y) = (I.cols - x, y ) - - What would happen? It is easily seen that the image would flip in the :math:`x` direction. For instance, consider the input image: - - .. image:: images/Remap_Tutorial_Theory_0.jpg - :alt: Original test image - :width: 120pt - :align: center - - observe how the red circle changes positions with respect to x (considering :math:`x` the horizontal direction): - - .. image:: images/Remap_Tutorial_Theory_1.jpg - :alt: Original test image - :width: 120pt - :align: center - -* In OpenCV, the function :remap:`remap <>` offers a simple remapping implementation. - -Code -==== - -#. **What does this program do?** - - * Loads an image - * Each second, apply 1 of 4 different remapping processes to the image and display them indefinitely in a window. - * Wait for the user to exit the program - -#. The tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - - using namespace cv; - - /// Global variables - Mat src, dst; - Mat map_x, map_y; - char* remap_window = "Remap demo"; - int ind = 0; - - /// Function Headers - void update_map( void ); - - /* - * @function main - */ - int main( int argc, char** argv ) - { - /// Load the image - src = imread( argv[1], 1 ); - - /// Create dst, map_x and map_y with the same size as src: - dst.create( src.size(), src.type() ); - map_x.create( src.size(), CV_32FC1 ); - map_y.create( src.size(), CV_32FC1 ); - - /// Create window - namedWindow( remap_window, WINDOW_AUTOSIZE ); - - /// Loop - while( true ) - { - /// Each 1 sec. Press ESC to exit the program - int c = waitKey( 1000 ); - - if( (char)c == 27 ) - { break; } - - /// Update map_x & map_y. Then apply remap - update_map(); - remap( src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) ); - - /// Display results - imshow( remap_window, dst ); - } - return 0; - } - - /* - * @function update_map - * @brief Fill the map_x and map_y matrices with 4 types of mappings - */ - void update_map( void ) - { - ind = ind%4; - - for( int j = 0; j < src.rows; j++ ) - { for( int i = 0; i < src.cols; i++ ) - { - switch( ind ) - { - case 0: - if( i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75 ) - { - map_x.at(j,i) = 2*( i - src.cols*0.25 ) + 0.5 ; - map_y.at(j,i) = 2*( j - src.rows*0.25 ) + 0.5 ; - } - else - { map_x.at(j,i) = 0 ; - map_y.at(j,i) = 0 ; - } - break; - case 1: - map_x.at(j,i) = i ; - map_y.at(j,i) = src.rows - j ; - break; - case 2: - map_x.at(j,i) = src.cols - i ; - map_y.at(j,i) = j ; - break; - case 3: - map_x.at(j,i) = src.cols - i ; - map_y.at(j,i) = src.rows - j ; - break; - } // end of switch - } - } - ind++; - } - -Explanation -=========== - -#. Create some variables we will use: - - .. code-block:: cpp - - Mat src, dst; - Mat map_x, map_y; - char* remap_window = "Remap demo"; - int ind = 0; - -#. Load an image: - - .. code-block:: cpp - - src = imread( argv[1], 1 ); - -#. Create the destination image and the two mapping matrices (for x and y ) - - .. code-block:: cpp - - dst.create( src.size(), src.type() ); - map_x.create( src.size(), CV_32FC1 ); - map_y.create( src.size(), CV_32FC1 ); - -#. Create a window to display results - - .. code-block:: cpp - - namedWindow( remap_window, WINDOW_AUTOSIZE ); - -#. Establish a loop. Each 1000 ms we update our mapping matrices (*mat_x* and *mat_y*) and apply them to our source image: - - .. code-block:: cpp - - while( true ) - { - /// Each 1 sec. Press ESC to exit the program - int c = waitKey( 1000 ); - - if( (char)c == 27 ) - { break; } - - /// Update map_x & map_y. Then apply remap - update_map(); - remap( src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) ); - - /// Display results - imshow( remap_window, dst ); - } - - The function that applies the remapping is :remap:`remap <>`. We give the following arguments: - - * **src**: Source image - * **dst**: Destination image of same size as *src* - * **map_x**: The mapping function in the x direction. It is equivalent to the first component of :math:`h(i,j)` - * **map_y**: Same as above, but in y direction. Note that *map_y* and *map_x* are both of the same size as *src* - * **INTER_LINEAR**: The type of interpolation to use for non-integer pixels. This is by default. - * **BORDER_CONSTANT**: Default - - How do we update our mapping matrices *mat_x* and *mat_y*? Go on reading: - -#. **Updating the mapping matrices:** We are going to perform 4 different mappings: - - a. Reduce the picture to half its size and will display it in the middle: - - .. math:: - - h(i,j) = ( 2*i - src.cols/2 + 0.5, 2*j - src.rows/2 + 0.5) - - for all pairs :math:`(i,j)` such that: :math:`\dfrac{src.cols}{4} src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75 ) - { - map_x.at(j,i) = 2*( i - src.cols*0.25 ) + 0.5 ; - map_y.at(j,i) = 2*( j - src.rows*0.25 ) + 0.5 ; - } - else - { map_x.at(j,i) = 0 ; - map_y.at(j,i) = 0 ; - } - break; - case 1: - map_x.at(j,i) = i ; - map_y.at(j,i) = src.rows - j ; - break; - case 2: - map_x.at(j,i) = src.cols - i ; - map_y.at(j,i) = j ; - break; - case 3: - map_x.at(j,i) = src.cols - i ; - map_y.at(j,i) = src.rows - j ; - break; - } // end of switch - } - } - ind++; - } - - -Result -====== - -#. After compiling the code above, you can execute it giving as argument an image path. For instance, by using the following image: - - .. image:: images/Remap_Tutorial_Original_Image.jpg - :alt: Original test image - :width: 250pt - :align: center - -#. This is the result of reducing it to half the size and centering it: - - .. image:: images/Remap_Tutorial_Result_0.jpg - :alt: Result 0 for remapping - :width: 250pt - :align: center - -#. Turning it upside down: - - .. image:: images/Remap_Tutorial_Result_1.jpg - :alt: Result 0 for remapping - :width: 250pt - :align: center - -#. Reflecting it in the x direction: - - .. image:: images/Remap_Tutorial_Result_2.jpg - :alt: Result 0 for remapping - :width: 250pt - :align: center - -#. Reflecting it in both directions: - -.. image:: images/Remap_Tutorial_Result_3.jpg - :alt: Result 0 for remapping - :width: 250pt - :align: center diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.rst b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.rst deleted file mode 100644 index 9dd8475a4c..0000000000 --- a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.rst +++ /dev/null @@ -1,276 +0,0 @@ -.. _sobel_derivatives: - -Sobel Derivatives -****************** - - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :sobel:`Sobel <>` to calculate the derivatives from an image. - * Use the OpenCV function :scharr:`Scharr <>` to calculate a more accurate derivative for a kernel of size :math:`3 \cdot 3` - -Theory -======== - -.. note:: - The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. - - -#. In the last two tutorials we have seen applicative examples of convolutions. One of the most important convolutions is the computation of derivatives in an image (or an approximation to them). - -#. Why may be important the calculus of the derivatives in an image? Let's imagine we want to detect the *edges* present in the image. For instance: - - - .. image:: images/Sobel_Derivatives_Tutorial_Theory_0.jpg - :alt: How intensity changes in an edge - :align: center - - You can easily notice that in an *edge*, the pixel intensity *changes* in a notorious way. A good way to express *changes* is by using *derivatives*. A high change in gradient indicates a major change in the image. - -#. To be more graphical, let's assume we have a 1D-image. An edge is shown by the "jump" in intensity in the plot below: - - .. image:: images/Sobel_Derivatives_Tutorial_Theory_Intensity_Function.jpg - :alt: Intensity Plot for an edge - :align: center - -#. The edge "jump" can be seen more easily if we take the first derivative (actually, here appears as a maximum) - - .. image:: images/Sobel_Derivatives_Tutorial_Theory_dIntensity_Function.jpg - :alt: First derivative of Intensity - Plot for an edge - :align: center - -#. So, from the explanation above, we can deduce that a method to detect edges in an image can be performed by locating pixel locations where the gradient is higher than its neighbors (or to generalize, higher than a threshold). - -#. More detailed explanation, please refer to **Learning OpenCV** by Bradski and Kaehler - -Sobel Operator ---------------- - -#. The Sobel Operator is a discrete differentiation operator. It computes an approximation of the gradient of an image intensity function. - -#. The Sobel Operator combines Gaussian smoothing and differentiation. - -Formulation -^^^^^^^^^^^^ -Assuming that the image to be operated is :math:`I`: - -#. We calculate two derivatives: - - a. **Horizontal changes**: This is computed by convolving :math:`I` with a kernel :math:`G_{x}` with odd size. For example for a kernel size of 3, :math:`G_{x}` would be computed as: - - .. math:: - - G_{x} = \begin{bmatrix} - -1 & 0 & +1 \\ - -2 & 0 & +2 \\ - -1 & 0 & +1 - \end{bmatrix} * I - - b. **Vertical changes**: This is computed by convolving :math:`I` with a kernel :math:`G_{y}` with odd size. For example for a kernel size of 3, :math:`G_{y}` would be computed as: - - .. math:: - - G_{y} = \begin{bmatrix} - -1 & -2 & -1 \\ - 0 & 0 & 0 \\ - +1 & +2 & +1 - \end{bmatrix} * I - -#. At each point of the image we calculate an approximation of the *gradient* in that point by combining both results above: - - .. math:: - - G = \sqrt{ G_{x}^{2} + G_{y}^{2} } - - Although sometimes the following simpler equation is used: - - .. math:: - - G = |G_{x}| + |G_{y}| - - -.. note:: - - When the size of the kernel is :math:`3`, the Sobel kernel shown above may produce noticeable inaccuracies (after all, Sobel is only an approximation of the derivative). OpenCV addresses this inaccuracy for kernels of size 3 by using the :scharr:`Scharr <>` function. This is as fast but more accurate than the standar Sobel function. It implements the following kernels: - - .. math:: - - G_{x} = \begin{bmatrix} - -3 & 0 & +3 \\ - -10 & 0 & +10 \\ - -3 & 0 & +3 - \end{bmatrix} - - G_{y} = \begin{bmatrix} - -3 & -10 & -3 \\ - 0 & 0 & 0 \\ - +3 & +10 & +3 - \end{bmatrix} - - You can check out more information of this function in the OpenCV reference (:scharr:`Scharr <>`). Also, in the sample code below, you will notice that above the code for :sobel:`Sobel <>` function there is also code for the :scharr:`Scharr <>` function commented. Uncommenting it (and obviously commenting the Sobel stuff) should give you an idea of how this function works. - -Code -===== - -#. **What does this program do?** - - * Applies the *Sobel Operator* and generates as output an image with the detected *edges* bright on a darker background. - -#. The tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - #include - #include - - using namespace cv; - - /* @function main */ - int main( int argc, char** argv ) - { - - Mat src, src_gray; - Mat grad; - char* window_name = "Sobel Demo - Simple Edge Detector"; - int scale = 1; - int delta = 0; - int ddepth = CV_16S; - - int c; - - /// Load an image - src = imread( argv[1] ); - - if( !src.data ) - { return -1; } - - GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); - - /// Convert it to gray - cvtColor( src, src_gray, COLOR_RGB2GRAY ); - - /// Create window - namedWindow( window_name, WINDOW_AUTOSIZE ); - - /// Generate grad_x and grad_y - Mat grad_x, grad_y; - Mat abs_grad_x, abs_grad_y; - - /// Gradient X - //Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT ); - Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); - convertScaleAbs( grad_x, abs_grad_x ); - - /// Gradient Y - //Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT ); - Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT ); - convertScaleAbs( grad_y, abs_grad_y ); - - /// Total Gradient (approximate) - addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); - - imshow( window_name, grad ); - - waitKey(0); - - return 0; - } - - -Explanation -============= - -#. First we declare the variables we are going to use: - - .. code-block:: cpp - - Mat src, src_gray; - Mat grad; - char* window_name = "Sobel Demo - Simple Edge Detector"; - int scale = 1; - int delta = 0; - int ddepth = CV_16S; - -#. As usual we load our source image *src*: - - .. code-block:: cpp - - src = imread( argv[1] ); - - if( !src.data ) - { return -1; } - -#. First, we apply a :gaussian_blur:`GaussianBlur <>` to our image to reduce the noise ( kernel size = 3 ) - - .. code-block:: cpp - - GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT ); - -#. Now we convert our filtered image to grayscale: - - .. code-block:: cpp - - cvtColor( src, src_gray, COLOR_RGB2GRAY ); - -#. Second, we calculate the "*derivatives*" in *x* and *y* directions. For this, we use the function :sobel:`Sobel <>` as shown below: - - .. code-block:: cpp - - Mat grad_x, grad_y; - Mat abs_grad_x, abs_grad_y; - - /// Gradient X - Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); - /// Gradient Y - Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT ); - - The function takes the following arguments: - - * *src_gray*: In our example, the input image. Here it is *CV_8U* - * *grad_x*/*grad_y*: The output image. - * *ddepth*: The depth of the output image. We set it to *CV_16S* to avoid overflow. - * *x_order*: The order of the derivative in **x** direction. - * *y_order*: The order of the derivative in **y** direction. - * *scale*, *delta* and *BORDER_DEFAULT*: We use default values. - - Notice that to calculate the gradient in *x* direction we use: :math:`x_{order}= 1` and :math:`y_{order} = 0`. We do analogously for the *y* direction. - -#. We convert our partial results back to *CV_8U*: - - .. code-block:: cpp - - convertScaleAbs( grad_x, abs_grad_x ); - convertScaleAbs( grad_y, abs_grad_y ); - - -#. Finally, we try to approximate the *gradient* by adding both directional gradients (note that this is not an exact calculation at all! but it is good for our purposes). - - .. code-block:: cpp - - addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); - -#. Finally, we show our result: - - .. code-block:: cpp - - imshow( window_name, grad ); - - - -Results -======== - -#. Here is the output of applying our basic detector to *lena.jpg*: - - - .. image:: images/Sobel_Derivatives_Tutorial_Result.jpg - :alt: Result of applying Sobel operator to lena.jpg - :width: 300pt - :align: center diff --git a/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.rst b/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.rst deleted file mode 100644 index 8d4a29d000..0000000000 --- a/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.rst +++ /dev/null @@ -1,308 +0,0 @@ -.. _warp_affine: - -Affine Transformations -********************** - - -Goal -==== - -In this tutorial you will learn how to: - -a. Use the OpenCV function :warp_affine:`warpAffine <>` to implement simple remapping routines. -b. Use the OpenCV function :get_rotation_matrix_2d:`getRotationMatrix2D <>` to obtain a :math:`2 \times 3` rotation matrix - - -Theory -====== - -What is an Affine Transformation? ----------------------------------- - -#. It is any transformation that can be expressed in the form of a *matrix multiplication* (linear transformation) followed by a *vector addition* (translation). - -#. From the above, We can use an Affine Transformation to express: - - a. Rotations (linear transformation) - b. Translations (vector addition) - c. Scale operations (linear transformation) - - you can see that, in essence, an Affine Transformation represents a **relation** between two images. - -#. The usual way to represent an Affine Transform is by using a :math:`2 \times 3` matrix. - - .. math:: - - A = \begin{bmatrix} - a_{00} & a_{01} \\ - a_{10} & a_{11} - \end{bmatrix}_{2 \times 2} - B = \begin{bmatrix} - b_{00} \\ - b_{10} - \end{bmatrix}_{2 \times 1} - - M = \begin{bmatrix} - A & B - \end{bmatrix} - = - \begin{bmatrix} - a_{00} & a_{01} & b_{00} \\ - a_{10} & a_{11} & b_{10} - \end{bmatrix}_{2 \times 3} - - Considering that we want to transform a 2D vector :math:`X = \begin{bmatrix}x \\ y\end{bmatrix}` by using :math:`A` and :math:`B`, we can do it equivalently with: - - - :math:`T = A \cdot \begin{bmatrix}x \\ y\end{bmatrix} + B` or :math:`T = M \cdot [x, y, 1]^{T}` - - .. math:: - - T = \begin{bmatrix} - a_{00}x + a_{01}y + b_{00} \\ - a_{10}x + a_{11}y + b_{10} - \end{bmatrix} - - -How do we get an Affine Transformation? ---------------------------------------- - -1. Excellent question. We mentioned that an Affine Transformation is basically a **relation** between two images. The information about this relation can come, roughly, in two ways: - - a. We know both :math:`X` and `T` and we also know that they are related. Then our job is to find :math:`M` - - b. We know :math:`M` and :math:`X`. To obtain :math:`T` we only need to apply :math:`T = M \cdot X`. Our information for :math:`M` may be explicit (i.e. have the 2-by-3 matrix) or it can come as a geometric relation between points. - -2. Let's explain a little bit better (b). Since :math:`M` relates 02 images, we can analyze the simplest case in which it relates three points in both images. Look at the figure below: - - .. image:: images/Warp_Affine_Tutorial_Theory_0.jpg - :alt: Theory of Warp Affine - :width: 350pt - :align: center - - the points 1, 2 and 3 (forming a triangle in image 1) are mapped into image 2, still forming a triangle, but now they have changed notoriously. If we find the Affine Transformation with these 3 points (you can choose them as you like), then we can apply this found relation to the whole pixels in the image. - - -Code -==== - -#. **What does this program do?** - - * Loads an image - * Applies an Affine Transform to the image. This Transform is obtained from the relation between three points. We use the function :warp_affine:`warpAffine <>` for that purpose. - * Applies a Rotation to the image after being transformed. This rotation is with respect to the image center - * Waits until the user exits the program - -#. The tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - - using namespace cv; - using namespace std; - - /// Global variables - char* source_window = "Source image"; - char* warp_window = "Warp"; - char* warp_rotate_window = "Warp + Rotate"; - - /* @function main */ - int main( int argc, char** argv ) - { - Point2f srcTri[3]; - Point2f dstTri[3]; - - Mat rot_mat( 2, 3, CV_32FC1 ); - Mat warp_mat( 2, 3, CV_32FC1 ); - Mat src, warp_dst, warp_rotate_dst; - - /// Load the image - src = imread( argv[1], 1 ); - - /// Set the dst image the same type and size as src - warp_dst = Mat::zeros( src.rows, src.cols, src.type() ); - - /// Set your 3 points to calculate the Affine Transform - srcTri[0] = Point2f( 0,0 ); - srcTri[1] = Point2f( src.cols - 1, 0 ); - srcTri[2] = Point2f( 0, src.rows - 1 ); - - dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 ); - dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 ); - dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 ); - - /// Get the Affine Transform - warp_mat = getAffineTransform( srcTri, dstTri ); - - /// Apply the Affine Transform just found to the src image - warpAffine( src, warp_dst, warp_mat, warp_dst.size() ); - - /* Rotating the image after Warp */ - - /// Compute a rotation matrix with respect to the center of the image - Point center = Point( warp_dst.cols/2, warp_dst.rows/2 ); - double angle = -50.0; - double scale = 0.6; - - /// Get the rotation matrix with the specifications above - rot_mat = getRotationMatrix2D( center, angle, scale ); - - /// Rotate the warped image - warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() ); - - /// Show what you got - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); - - namedWindow( warp_window, WINDOW_AUTOSIZE ); - imshow( warp_window, warp_dst ); - - namedWindow( warp_rotate_window, WINDOW_AUTOSIZE ); - imshow( warp_rotate_window, warp_rotate_dst ); - - /// Wait until user exits the program - waitKey(0); - - return 0; - } - -Explanation -=========== - -#. Declare some variables we will use, such as the matrices to store our results and 2 arrays of points to store the 2D points that define our Affine Transform. - - .. code-block:: cpp - - Point2f srcTri[3]; - Point2f dstTri[3]; - - Mat rot_mat( 2, 3, CV_32FC1 ); - Mat warp_mat( 2, 3, CV_32FC1 ); - Mat src, warp_dst, warp_rotate_dst; - -#. Load an image: - - .. code-block:: cpp - - src = imread( argv[1], 1 ); - -#. Initialize the destination image as having the same size and type as the source: - - .. code-block:: cpp - - warp_dst = Mat::zeros( src.rows, src.cols, src.type() ); - -#. **Affine Transform:** As we explained lines above, we need two sets of 3 points to derive the affine transform relation. Take a look: - - .. code-block:: cpp - - srcTri[0] = Point2f( 0,0 ); - srcTri[1] = Point2f( src.cols - 1, 0 ); - srcTri[2] = Point2f( 0, src.rows - 1 ); - - dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 ); - dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 ); - dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 ); - - You may want to draw the points to make a better idea of how they change. Their locations are approximately the same as the ones depicted in the example figure (in the Theory section). You may note that the size and orientation of the triangle defined by the 3 points change. - -#. Armed with both sets of points, we calculate the Affine Transform by using OpenCV function :get_affine_transform:`getAffineTransform <>`: - - .. code-block:: cpp - - warp_mat = getAffineTransform( srcTri, dstTri ); - - - We get as an output a :math:`2 \times 3` matrix (in this case **warp_mat**) - -#. We apply the Affine Transform just found to the src image - - .. code-block:: cpp - - warpAffine( src, warp_dst, warp_mat, warp_dst.size() ); - - with the following arguments: - - * **src**: Input image - * **warp_dst**: Output image - * **warp_mat**: Affine transform - * **warp_dst.size()**: The desired size of the output image - - We just got our first transformed image! We will display it in one bit. Before that, we also want to rotate it... - -#. **Rotate:** - To rotate an image, we need to know two things: - - a. The center with respect to which the image will rotate - b. The angle to be rotated. In OpenCV a positive angle is counter-clockwise - c. *Optional:* A scale factor - - We define these parameters with the following snippet: - - .. code-block:: cpp - - Point center = Point( warp_dst.cols/2, warp_dst.rows/2 ); - double angle = -50.0; - double scale = 0.6; - -#. We generate the rotation matrix with the OpenCV function :get_rotation_matrix_2d:`getRotationMatrix2D <>`, which returns a :math:`2 \times 3` matrix (in this case *rot_mat*) - - .. code-block:: cpp - - rot_mat = getRotationMatrix2D( center, angle, scale ); - -#. We now apply the found rotation to the output of our previous Transformation. - - .. code-block:: cpp - - warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() ); - -#. Finally, we display our results in two windows plus the original image for good measure: - - .. code-block:: cpp - - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); - - namedWindow( warp_window, WINDOW_AUTOSIZE ); - imshow( warp_window, warp_dst ); - - namedWindow( warp_rotate_window, WINDOW_AUTOSIZE ); - imshow( warp_rotate_window, warp_rotate_dst ); - - -#. We just have to wait until the user exits the program - - .. code-block:: cpp - - waitKey(0); - - - -Result -====== - -#. After compiling the code above, we can give it the path of an image as argument. For instance, for a picture like: - - .. image:: images/Warp_Affine_Tutorial_Original_Image.jpg - :alt: Original image - :width: 250pt - :align: center - - after applying the first Affine Transform we obtain: - - .. image:: images/Warp_Affine_Tutorial_Result_Warp.jpg - :alt: Original image - :width: 250pt - :align: center - - and finally, after applying a negative rotation (remember negative means clockwise) and a scale factor, we get: - - .. image:: images/Warp_Affine_Tutorial_Result_Warp_Rotate.jpg - :alt: Original image - :width: 250pt - :align: center diff --git a/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.rst b/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.rst deleted file mode 100644 index e533933b67..0000000000 --- a/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.rst +++ /dev/null @@ -1,281 +0,0 @@ -.. _Morphology_2: - -More Morphology Transformations -********************************* - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :morphology_ex:`morphologyEx <>` to apply Morphological Transformation such as: - - + Opening - + Closing - + Morphological Gradient - + Top Hat - + Black Hat - -Theory -======= - -.. note:: - The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. - -In the previous tutorial we covered two basic Morphology operations: - -.. container:: enumeratevisibleitemswithsquare - - * Erosion - * Dilation. - -Based on these two we can effectuate more sophisticated transformations to our images. Here we discuss briefly 05 operations offered by OpenCV: - -Opening ---------- - -* It is obtained by the erosion of an image followed by a dilation. - - .. math:: - - dst = open( src, element) = dilate( erode( src, element ) ) - -* Useful for removing small objects (it is assumed that the objects are bright on a dark foreground) - -* For instance, check out the example below. The image at the left is the original and the image at the right is the result after applying the opening transformation. We can observe that the small spaces in the corners of the letter tend to dissapear. - - .. image:: images/Morphology_2_Tutorial_Theory_Opening.png - :alt: Opening - :align: center - -Closing ---------- - -* It is obtained by the dilation of an image followed by an erosion. - - .. math:: - - dst = close( src, element ) = erode( dilate( src, element ) ) - -* Useful to remove small holes (dark regions). - - .. image:: images/Morphology_2_Tutorial_Theory_Closing.png - :alt: Closing example - :align: center - - -Morphological Gradient ------------------------- - -* It is the difference between the dilation and the erosion of an image. - - .. math:: - - dst = morph_{grad}( src, element ) = dilate( src, element ) - erode( src, element ) - -* It is useful for finding the outline of an object as can be seen below: - - .. image:: images/Morphology_2_Tutorial_Theory_Gradient.png - :alt: Gradient - :align: center - - -Top Hat ---------- - -* It is the difference between an input image and its opening. - - .. math:: - - dst = tophat( src, element ) = src - open( src, element ) - - .. image:: images/Morphology_2_Tutorial_Theory_TopHat.png - :alt: Top Hat - :align: center - -Black Hat ----------- - -* It is the difference between the closing and its input image - - .. math:: - - dst = blackhat( src, element ) = close( src, element ) - src - - .. image:: images/Morphology_2_Tutorial_Theory_BlackHat.png - :alt: Black Hat - :align: center - -Code -====== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - #include - #include - - using namespace cv; - - /// Global variables - Mat src, dst; - - int morph_elem = 0; - int morph_size = 0; - int morph_operator = 0; - int const max_operator = 4; - int const max_elem = 2; - int const max_kernel_size = 21; - - char* window_name = "Morphology Transformations Demo"; - - /* Function Headers */ - void Morphology_Operations( int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load an image - src = imread( argv[1] ); - - if( !src.data ) - { return -1; } - - /// Create window - namedWindow( window_name, WINDOW_AUTOSIZE ); - - /// Create Trackbar to select Morphology operation - createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations ); - - /// Create Trackbar to select kernel type - createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name, - &morph_elem, max_elem, - Morphology_Operations ); - - /// Create Trackbar to choose kernel size - createTrackbar( "Kernel size:\n 2n +1", window_name, - &morph_size, max_kernel_size, - Morphology_Operations ); - - /// Default start - Morphology_Operations( 0, 0 ); - - waitKey(0); - return 0; - } - - /* - * @function Morphology_Operations - */ - void Morphology_Operations( int, void* ) - { - // Since MORPH_X : 2,3,4,5 and 6 - int operation = morph_operator + 2; - - Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) ); - - /// Apply the specified morphology operation - morphologyEx( src, dst, operation, element ); - imshow( window_name, dst ); - } - - -Explanation -============= - -#. Let's check the general structure of the program: - - * Load an image - - * Create a window to display results of the Morphological operations - - * Create 03 Trackbars for the user to enter parameters: - - * The first trackbar **"Operator"** returns the kind of morphology operation to use (**morph_operator**). - - .. code-block:: cpp - - createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", - window_name, &morph_operator, max_operator, - Morphology_Operations ); - - - - * The second trackbar **"Element"** returns **morph_elem**, which indicates what kind of structure our kernel is: - - .. code-block:: cpp - - createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name, - &morph_elem, max_elem, - Morphology_Operations ); - - * The final trackbar **"Kernel Size"** returns the size of the kernel to be used (**morph_size**) - - .. code-block:: cpp - - createTrackbar( "Kernel size:\n 2n +1", window_name, - &morph_size, max_kernel_size, - Morphology_Operations ); - - - * Every time we move any slider, the user's function **Morphology_Operations** will be called to effectuate a new morphology operation and it will update the output image based on the current trackbar values. - - .. code-block:: cpp - - /* - * @function Morphology_Operations - */ - void Morphology_Operations( int, void* ) - { - // Since MORPH_X : 2,3,4,5 and 6 - int operation = morph_operator + 2; - - Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) ); - - /// Apply the specified morphology operation - morphologyEx( src, dst, operation, element ); - imshow( window_name, dst ); - } - - - We can observe that the key function to perform the morphology transformations is :morphology_ex:`morphologyEx <>`. In this example we use four arguments (leaving the rest as defaults): - - * **src** : Source (input) image - * **dst**: Output image - * **operation**: The kind of morphology transformation to be performed. Note that we have 5 alternatives: - - + *Opening*: MORPH_OPEN : 2 - + *Closing*: MORPH_CLOSE: 3 - + *Gradient*: MORPH_GRADIENT: 4 - + *Top Hat*: MORPH_TOPHAT: 5 - + *Black Hat*: MORPH_BLACKHAT: 6 - - As you can see the values range from <2-6>, that is why we add (+2) to the values entered by the Trackbar: - - .. code-block:: cpp - - int operation = morph_operator + 2; - - * **element**: The kernel to be used. We use the function :get_structuring_element:`getStructuringElement <>` to define our own structure. - - - -Results -======== - -* After compiling the code above we can execute it giving an image path as an argument. For this tutorial we use as input the image: **baboon.png**: - - .. image:: images/Morphology_2_Tutorial_Original_Image.jpg - :alt: Morphology 2: Original image - :align: center - -* And here are two snapshots of the display window. The first picture shows the output after using the operator **Opening** with a cross kernel. The second picture (right side, shows the result of using a **Blackhat** operator with an ellipse kernel. - - .. image:: images/Morphology_2_Tutorial_Result.jpg - :alt: Morphology 2: Result sample - :align: center diff --git a/doc/tutorials/imgproc/pyramids/pyramids.rst b/doc/tutorials/imgproc/pyramids/pyramids.rst deleted file mode 100644 index a77f351b82..0000000000 --- a/doc/tutorials/imgproc/pyramids/pyramids.rst +++ /dev/null @@ -1,261 +0,0 @@ -.. _Pyramids: - -Image Pyramids -*************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV functions :pyr_up:`pyrUp <>` and :pyr_down:`pyrDown <>` to downsample or upsample a given image. - -Theory -======= - -.. note:: - The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. - -.. container:: enumeratevisibleitemswithsquare - - * Usually we need to convert an image to a size different than its original. For this, there are two possible options: - - #. *Upsize* the image (zoom in) or - #. *Downsize* it (zoom out). - - * Although there is a *geometric transformation* function in OpenCV that -literally- resize an image (:resize:`resize <>`, which we will show in a future tutorial), in this section we analyze first the use of **Image Pyramids**, which are widely applied in a huge range of vision applications. - - -Image Pyramid --------------- - -.. container:: enumeratevisibleitemswithsquare - - * An image pyramid is a collection of images - all arising from a single original image - that are successively downsampled until some desired stopping point is reached. - - * There are two common kinds of image pyramids: - - * **Gaussian pyramid:** Used to downsample images - - * **Laplacian pyramid:** Used to reconstruct an upsampled image from an image lower in the pyramid (with less resolution) - - * In this tutorial we'll use the *Gaussian pyramid*. - -Gaussian Pyramid -^^^^^^^^^^^^^^^^^ - -* Imagine the pyramid as a set of layers in which the higher the layer, the smaller the size. - - .. image:: images/Pyramids_Tutorial_Pyramid_Theory.png - :alt: Pyramid figure - :align: center - -* Every layer is numbered from bottom to top, so layer :math:`(i+1)` (denoted as :math:`G_{i+1}` is smaller than layer :math:`i` (:math:`G_{i}`). - -* To produce layer :math:`(i+1)` in the Gaussian pyramid, we do the following: - - * Convolve :math:`G_{i}` with a Gaussian kernel: - - .. math:: - - \frac{1}{16} \begin{bmatrix} 1 & 4 & 6 & 4 & 1 \\ 4 & 16 & 24 & 16 & 4 \\ 6 & 24 & 36 & 24 & 6 \\ 4 & 16 & 24 & 16 & 4 \\ 1 & 4 & 6 & 4 & 1 \end{bmatrix} - - * Remove every even-numbered row and column. - -* You can easily notice that the resulting image will be exactly one-quarter the area of its predecessor. Iterating this process on the input image :math:`G_{0}` (original image) produces the entire pyramid. - -* The procedure above was useful to downsample an image. What if we want to make it bigger?: - - * First, upsize the image to twice the original in each dimension, wit the new even rows and columns filled with zeros (:math:`0`) - - * Perform a convolution with the same kernel shown above (multiplied by 4) to approximate the values of the "missing pixels" - -* These two procedures (downsampling and upsampling as explained above) are implemented by the OpenCV functions :pyr_up:`pyrUp <>` and :pyr_down:`pyrDown <>`, as we will see in an example with the code below: - -.. note:: - When we reduce the size of an image, we are actually *losing* information of the image. - -Code -====== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - #include - #include - #include - - using namespace cv; - - /// Global variables - Mat src, dst, tmp; - char* window_name = "Pyramids Demo"; - - - /* - * @function main - */ - int main( int argc, char** argv ) - { - /// General instructions - printf( "\n Zoom In-Out demo \n " ); - printf( "------------------ \n" ); - printf( " * [u] -> Zoom in \n" ); - printf( " * [d] -> Zoom out \n" ); - printf( " * [ESC] -> Close program \n \n" ); - - /// Test image - Make sure it s divisible by 2^{n} - src = imread( "../images/chicky_512.jpg" ); - if( !src.data ) - { printf(" No data! -- Exiting the program \n"); - return -1; } - - tmp = src; - dst = tmp; - - /// Create window - namedWindow( window_name, WINDOW_AUTOSIZE ); - imshow( window_name, dst ); - - /// Loop - while( true ) - { - int c; - c = waitKey(10); - - if( (char)c == 27 ) - { break; } - if( (char)c == 'u' ) - { pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) ); - printf( "** Zoom In: Image x 2 \n" ); - } - else if( (char)c == 'd' ) - { pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) ); - printf( "** Zoom Out: Image / 2 \n" ); - } - - imshow( window_name, dst ); - tmp = dst; - } - return 0; - } - -Explanation -============= - -#. Let's check the general structure of the program: - - * Load an image (in this case it is defined in the program, the user does not have to enter it as an argument) - - .. code-block:: cpp - - /// Test image - Make sure it s divisible by 2^{n} - src = imread( "../images/chicky_512.jpg" ); - if( !src.data ) - { printf(" No data! -- Exiting the program \n"); - return -1; } - - * Create a Mat object to store the result of the operations (*dst*) and one to save temporal results (*tmp*). - - .. code-block:: cpp - - Mat src, dst, tmp; - /* ... */ - tmp = src; - dst = tmp; - - - - * Create a window to display the result - - .. code-block:: cpp - - namedWindow( window_name, WINDOW_AUTOSIZE ); - imshow( window_name, dst ); - - * Perform an infinite loop waiting for user input. - - .. code-block:: cpp - - while( true ) - { - int c; - c = waitKey(10); - - if( (char)c == 27 ) - { break; } - if( (char)c == 'u' ) - { pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) ); - printf( "** Zoom In: Image x 2 \n" ); - } - else if( (char)c == 'd' ) - { pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) ); - printf( "** Zoom Out: Image / 2 \n" ); - } - - imshow( window_name, dst ); - tmp = dst; - } - - - Our program exits if the user presses *ESC*. Besides, it has two options: - - * **Perform upsampling (after pressing 'u')** - - .. code-block:: cpp - - pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) - - We use the function :pyr_up:`pyrUp <>` with 03 arguments: - - * *tmp*: The current image, it is initialized with the *src* original image. - * *dst*: The destination image (to be shown on screen, supposedly the double of the input image) - * *Size( tmp.cols*2, tmp.rows*2 )* : The destination size. Since we are upsampling, :pyr_up:`pyrUp <>` expects a size double than the input image (in this case *tmp*). - - * **Perform downsampling (after pressing 'd')** - - .. code-block:: cpp - - pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) - - Similarly as with :pyr_up:`pyrUp <>`, we use the function :pyr_down:`pyrDown <>` with 03 arguments: - - * *tmp*: The current image, it is initialized with the *src* original image. - * *dst*: The destination image (to be shown on screen, supposedly half the input image) - * *Size( tmp.cols/2, tmp.rows/2 )* : The destination size. Since we are upsampling, :pyr_down:`pyrDown <>` expects half the size the input image (in this case *tmp*). - - * Notice that it is important that the input image can be divided by a factor of two (in both dimensions). Otherwise, an error will be shown. - - * Finally, we update the input image **tmp** with the current image displayed, so the subsequent operations are performed on it. - - .. code-block:: cpp - - tmp = dst; - - - -Results -======== - -* After compiling the code above we can test it. The program calls an image **chicky_512.jpg** that comes in the *tutorial_code/image* folder. Notice that this image is :math:`512 \times 512`, hence a downsample won't generate any error (:math:`512 = 2^{9}`). The original image is shown below: - - .. image:: images/Pyramids_Tutorial_Original_Image.jpg - :alt: Pyramids: Original image - :align: center - -* First we apply two successive :pyr_down:`pyrDown <>` operations by pressing 'd'. Our output is: - - .. image:: images/Pyramids_Tutorial_PyrDown_Result.jpg - :alt: Pyramids: PyrDown Result - :align: center - -* Note that we should have lost some resolution due to the fact that we are diminishing the size of the image. This is evident after we apply :pyr_up:`pyrUp <>` twice (by pressing 'u'). Our output is now: - - .. image:: images/Pyramids_Tutorial_PyrUp_Result.jpg - :alt: Pyramids: PyrUp Result - :align: center diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.rst b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.rst deleted file mode 100644 index ed3eadd050..0000000000 --- a/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.rst +++ /dev/null @@ -1,123 +0,0 @@ -.. _bounding_rects_circles: - - -Creating Bounding boxes and circles for contours -************************************************* - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :bounding_rect:`boundingRect <>` - * Use the OpenCV function :min_enclosing_circle:`minEnclosingCircle <>` - - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - #include - - using namespace cv; - using namespace std; - - Mat src; Mat src_gray; - int thresh = 100; - int max_thresh = 255; - RNG rng(12345); - - /// Function header - void thresh_callback(int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load source image and convert it to gray - src = imread( argv[1], 1 ); - - /// Convert image to gray and blur it - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - blur( src_gray, src_gray, Size(3,3) ); - - /// Create Window - char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); - - createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); - thresh_callback( 0, 0 ); - - waitKey(0); - return(0); - } - - /* @function thresh_callback */ - void thresh_callback(int, void* ) - { - Mat threshold_output; - vector > contours; - vector hierarchy; - - /// Detect edges using Threshold - threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); - /// Find contours - findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) ); - - /// Approximate contours to polygons + get bounding rects and circles - vector > contours_poly( contours.size() ); - vector boundRect( contours.size() ); - vectorcenter( contours.size() ); - vectorradius( contours.size() ); - - for( int i = 0; i < contours.size(); i++ ) - { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true ); - boundRect[i] = boundingRect( Mat(contours_poly[i]) ); - minEnclosingCircle( (Mat)contours_poly[i], center[i], radius[i] ); - } - - - /// Draw polygonal contour + bonding rects + circles - Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); - for( int i = 0; i< contours.size(); i++ ) - { - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - drawContours( drawing, contours_poly, i, color, 1, 8, vector(), 0, Point() ); - rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 ); - circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 ); - } - - /// Show in a window - namedWindow( "Contours", WINDOW_AUTOSIZE ); - imshow( "Contours", drawing ); - } - -Explanation -============ - -Result -====== - -#. Here it is: - - ========== ========== - |BRC_0| |BRC_1| - ========== ========== - - .. |BRC_0| image:: images/Bounding_Rects_Circles_Source_Image.jpg - :align: middle - - .. |BRC_1| image:: images/Bounding_Rects_Circles_Result.jpg - :align: middle diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.rst b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.rst deleted file mode 100644 index 12d00cea1a..0000000000 --- a/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.rst +++ /dev/null @@ -1,125 +0,0 @@ -.. _bounding_rotated_ellipses: - - -Creating Bounding rotated boxes and ellipses for contours -********************************************************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :min_area_rect:`minAreaRect <>` - * Use the OpenCV function :fit_ellipse:`fitEllipse <>` - - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - #include - - using namespace cv; - using namespace std; - - Mat src; Mat src_gray; - int thresh = 100; - int max_thresh = 255; - RNG rng(12345); - - /// Function header - void thresh_callback(int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load source image and convert it to gray - src = imread( argv[1], 1 ); - - /// Convert image to gray and blur it - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - blur( src_gray, src_gray, Size(3,3) ); - - /// Create Window - char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); - - createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); - thresh_callback( 0, 0 ); - - waitKey(0); - return(0); - } - - /* @function thresh_callback */ - void thresh_callback(int, void* ) - { - Mat threshold_output; - vector > contours; - vector hierarchy; - - /// Detect edges using Threshold - threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); - /// Find contours - findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) ); - - /// Find the rotated rectangles and ellipses for each contour - vector minRect( contours.size() ); - vector minEllipse( contours.size() ); - - for( int i = 0; i < contours.size(); i++ ) - { minRect[i] = minAreaRect( Mat(contours[i]) ); - if( contours[i].size() > 5 ) - { minEllipse[i] = fitEllipse( Mat(contours[i]) ); } - } - - /// Draw contours + rotated rects + ellipses - Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); - for( int i = 0; i< contours.size(); i++ ) - { - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - // contour - drawContours( drawing, contours, i, color, 1, 8, vector(), 0, Point() ); - // ellipse - ellipse( drawing, minEllipse[i], color, 2, 8 ); - // rotated rectangle - Point2f rect_points[4]; minRect[i].points( rect_points ); - for( int j = 0; j < 4; j++ ) - line( drawing, rect_points[j], rect_points[(j+1)%4], color, 1, 8 ); - } - - /// Show in a window - namedWindow( "Contours", WINDOW_AUTOSIZE ); - imshow( "Contours", drawing ); - } - -Explanation -============ - -Result -====== - -#. Here it is: - - ========== ========== - |BRE_0| |BRE_1| - ========== ========== - - .. |BRE_0| image:: images/Bounding_Rotated_Ellipses_Source_Image.jpg - :align: middle - - .. |BRE_1| image:: images/Bounding_Rotated_Ellipses_Result.jpg - :align: middle diff --git a/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.rst b/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.rst deleted file mode 100644 index 556f8913e1..0000000000 --- a/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.rst +++ /dev/null @@ -1,106 +0,0 @@ -.. _find_contours: - -Finding contours in your image -****************************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :find_contours:`findContours <>` - * Use the OpenCV function :draw_contours:`drawContours <>` - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - #include - - using namespace cv; - using namespace std; - - Mat src; Mat src_gray; - int thresh = 100; - int max_thresh = 255; - RNG rng(12345); - - /// Function header - void thresh_callback(int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load source image and convert it to gray - src = imread( argv[1], 1 ); - - /// Convert image to gray and blur it - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - blur( src_gray, src_gray, Size(3,3) ); - - /// Create Window - char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); - - createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback ); - thresh_callback( 0, 0 ); - - waitKey(0); - return(0); - } - - /* @function thresh_callback */ - void thresh_callback(int, void* ) - { - Mat canny_output; - vector > contours; - vector hierarchy; - - /// Detect edges using canny - Canny( src_gray, canny_output, thresh, thresh*2, 3 ); - /// Find contours - findContours( canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) ); - - /// Draw contours - Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); - for( int i = 0; i< contours.size(); i++ ) - { - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() ); - } - - /// Show in a window - namedWindow( "Contours", WINDOW_AUTOSIZE ); - imshow( "Contours", drawing ); - } - -Explanation -============ - -Result -====== - -#. Here it is: - - ============= ============= - |contour_0| |contour_1| - ============= ============= - - .. |contour_0| image:: images/Find_Contours_Original_Image.jpg - :align: middle - - .. |contour_1| image:: images/Find_Contours_Result.jpg - :align: middle diff --git a/doc/tutorials/imgproc/shapedescriptors/hull/hull.rst b/doc/tutorials/imgproc/shapedescriptors/hull/hull.rst deleted file mode 100644 index 81be2e5fb8..0000000000 --- a/doc/tutorials/imgproc/shapedescriptors/hull/hull.rst +++ /dev/null @@ -1,115 +0,0 @@ -.. _hull: - -Convex Hull -*********** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :convex_hull:`convexHull <>` - - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - #include - - using namespace cv; - using namespace std; - - Mat src; Mat src_gray; - int thresh = 100; - int max_thresh = 255; - RNG rng(12345); - - /// Function header - void thresh_callback(int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load source image and convert it to gray - src = imread( argv[1], 1 ); - - /// Convert image to gray and blur it - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - blur( src_gray, src_gray, Size(3,3) ); - - /// Create Window - char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); - - createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); - thresh_callback( 0, 0 ); - - waitKey(0); - return(0); - } - - /* @function thresh_callback */ - void thresh_callback(int, void* ) - { - Mat src_copy = src.clone(); - Mat threshold_output; - vector > contours; - vector hierarchy; - - /// Detect edges using Threshold - threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); - - /// Find contours - findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) ); - - /// Find the convex hull object for each contour - vector >hull( contours.size() ); - for( int i = 0; i < contours.size(); i++ ) - { convexHull( Mat(contours[i]), hull[i], false ); } - - /// Draw contours + hull results - Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); - for( int i = 0; i< contours.size(); i++ ) - { - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - drawContours( drawing, contours, i, color, 1, 8, vector(), 0, Point() ); - drawContours( drawing, hull, i, color, 1, 8, vector(), 0, Point() ); - } - - /// Show in a window - namedWindow( "Hull demo", WINDOW_AUTOSIZE ); - imshow( "Hull demo", drawing ); - } - - -Explanation -============ - -Result -====== - -#. Here it is: - - ========== ========== - |Hull_0| |Hull_1| - ========== ========== - - .. |Hull_0| image:: images/Hull_Original_Image.jpg - :align: middle - - .. |Hull_1| image:: images/Hull_Result.jpg - :align: middle diff --git a/doc/tutorials/imgproc/shapedescriptors/moments/moments.rst b/doc/tutorials/imgproc/shapedescriptors/moments/moments.rst deleted file mode 100644 index 6f6090b545..0000000000 --- a/doc/tutorials/imgproc/shapedescriptors/moments/moments.rst +++ /dev/null @@ -1,135 +0,0 @@ -.. _moments: - - -Image Moments -************** - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :moments:`moments <>` - * Use the OpenCV function :contour_area:`contourArea <>` - * Use the OpenCV function :arc_length:`arcLength <>` - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - #include - - using namespace cv; - using namespace std; - - Mat src; Mat src_gray; - int thresh = 100; - int max_thresh = 255; - RNG rng(12345); - - /// Function header - void thresh_callback(int, void* ); - - /* @function main */ - int main( int argc, char** argv ) - { - /// Load source image and convert it to gray - src = imread( argv[1], 1 ); - - /// Convert image to gray and blur it - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - blur( src_gray, src_gray, Size(3,3) ); - - /// Create Window - char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); - - createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback ); - thresh_callback( 0, 0 ); - - waitKey(0); - return(0); - } - - /* @function thresh_callback */ - void thresh_callback(int, void* ) - { - Mat canny_output; - vector > contours; - vector hierarchy; - - /// Detect edges using canny - Canny( src_gray, canny_output, thresh, thresh*2, 3 ); - /// Find contours - findContours( canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) ); - - /// Get the moments - vector mu(contours.size() ); - for( int i = 0; i < contours.size(); i++ ) - { mu[i] = moments( contours[i], false ); } - - /// Get the mass centers: - vector mc( contours.size() ); - for( int i = 0; i < contours.size(); i++ ) - { mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); } - - /// Draw contours - Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); - for( int i = 0; i< contours.size(); i++ ) - { - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() ); - circle( drawing, mc[i], 4, color, -1, 8, 0 ); - } - - /// Show in a window - namedWindow( "Contours", WINDOW_AUTOSIZE ); - imshow( "Contours", drawing ); - - /// Calculate the area with the moments 00 and compare with the result of the OpenCV function - printf("\t Info: Area and Contour Length \n"); - for( int i = 0; i< contours.size(); i++ ) - { - printf(" * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f \n", i, mu[i].m00, contourArea(contours[i]), arcLength( contours[i], true ) ); - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() ); - circle( drawing, mc[i], 4, color, -1, 8, 0 ); - } - } - -Explanation -============ - -Result -====== - -#. Here it is: - - ========== ========== ========== - |MU_0| |MU_1| |MU_2| - ========== ========== ========== - - .. |MU_0| image:: images/Moments_Source_Image.jpg - :width: 250pt - :align: middle - - .. |MU_1| image:: images/Moments_Result1.jpg - :width: 250pt - :align: middle - - .. |MU_2| image:: images/Moments_Result2.jpg - :width: 250pt - :align: middle diff --git a/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.rst b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.rst deleted file mode 100644 index 1adb251713..0000000000 --- a/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.rst +++ /dev/null @@ -1,116 +0,0 @@ -.. _point_polygon_test: - -Point Polygon Test -******************* - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the OpenCV function :point_polygon_test:`pointPolygonTest <>` - - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - #include - #include - #include - - using namespace cv; - using namespace std; - - /* @function main */ - int main( int argc, char** argv ) - { - /// Create an image - const int r = 100; - Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8UC1 ); - - /// Create a sequence of points to make a contour: - vector vert(6); - - vert[0] = Point( 1.5*r, 1.34*r ); - vert[1] = Point( 1*r, 2*r ); - vert[2] = Point( 1.5*r, 2.866*r ); - vert[3] = Point( 2.5*r, 2.866*r ); - vert[4] = Point( 3*r, 2*r ); - vert[5] = Point( 2.5*r, 1.34*r ); - - /// Draw it in src - for( int j = 0; j < 6; j++ ) - { line( src, vert[j], vert[(j+1)%6], Scalar( 255 ), 3, 8 ); } - - /// Get the contours - vector > contours; vector hierarchy; - Mat src_copy = src.clone(); - - findContours( src_copy, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); - - /// Calculate the distances to the contour - Mat raw_dist( src.size(), CV_32FC1 ); - - for( int j = 0; j < src.rows; j++ ) - { for( int i = 0; i < src.cols; i++ ) - { raw_dist.at(j,i) = pointPolygonTest( contours[0], Point2f(i,j), true ); } - } - - double minVal; double maxVal; - minMaxLoc( raw_dist, &minVal, &maxVal, 0, 0, Mat() ); - minVal = abs(minVal); maxVal = abs(maxVal); - - /// Depicting the distances graphically - Mat drawing = Mat::zeros( src.size(), CV_8UC3 ); - - for( int j = 0; j < src.rows; j++ ) - { for( int i = 0; i < src.cols; i++ ) - { - if( raw_dist.at(j,i) < 0 ) - { drawing.at(j,i)[0] = 255 - (int) abs(raw_dist.at(j,i))*255/minVal; } - else if( raw_dist.at(j,i) > 0 ) - { drawing.at(j,i)[2] = 255 - (int) raw_dist.at(j,i)*255/maxVal; } - else - { drawing.at(j,i)[0] = 255; drawing.at(j,i)[1] = 255; drawing.at(j,i)[2] = 255; } - } - } - - /// Create Window and show your results - char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); - namedWindow( "Distance", WINDOW_AUTOSIZE ); - imshow( "Distance", drawing ); - - waitKey(0); - return(0); - } - -Explanation -============ - -Result -====== - -#. Here it is: - - ========== ========== - |PPT_0| |PPT_1| - ========== ========== - - .. |PPT_0| image:: images/Point_Polygon_Test_Source_Image.png - :align: middle - - .. |PPT_1| image:: images/Point_Polygon_Test_Result.jpg - :align: middle diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.markdown b/doc/tutorials/imgproc/table_of_content_imgproc.markdown similarity index 100% rename from doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.markdown rename to doc/tutorials/imgproc/table_of_content_imgproc.markdown diff --git a/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.rst b/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.rst deleted file mode 100644 index a371c02c87..0000000000 --- a/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.rst +++ /dev/null @@ -1,541 +0,0 @@ -.. _Table-Of-Content-ImgProc: - -*imgproc* module. Image Processing ------------------------------------------------------------ - -In this section you will learn about the image processing (manipulation) functions inside OpenCV. - -.. include:: ../../definitions/tocDefinitions.rst - - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |ImageProcessing_1| **Title:** :ref:`Smoothing` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Let's take a look at some basic linear filters! - - ===================== ============================================== - - .. |ImageProcessing_1| image:: images/Smoothing_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |ImageProcessing_2| **Title:** :ref:`Morphology_1` - - *Compatibility:* > OpenCV 2.0 - - Author: |Author_AnaH| - - Let's *change* the shape of objects! - - ===================== ============================================== - - .. |ImageProcessing_2| image:: images/Morphology_1_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ================= ================================================== - |Morphology_2| **Title:** :ref:`Morphology_2` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Here we investigate different morphology operators - - ================= ================================================== - - .. |Morphology_2| image:: images/Morphology_2_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |Pyramids| **Title:** :ref:`Pyramids` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - What if I need a bigger/smaller image? - - ===================== ============================================== - - .. |Pyramids| image:: images/Pyramids_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |Threshold| **Title:** :ref:`Basic_Threshold` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - After so much processing, it is time to decide which pixels stay! - - ===================== ============================================== - - .. |Threshold| image:: images/Threshold_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - -+ - ===================== ============================================== - |Filter_2D| **Title:** :ref:`filter_2d` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn to design our own filters by using OpenCV functions - - ===================== ============================================== - - .. |Filter_2D| image:: images/imgtrans/Filter_2D_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - -+ - ===================== ============================================== - |CopyMakeBorder| **Title:** :ref:`copyMakeBorderTutorial` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to pad our images! - - ===================== ============================================== - - .. |CopyMakeBorder| image:: images/imgtrans/CopyMakeBorder_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |SobelDerivatives| **Title:** :ref:`sobel_derivatives` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to calculate gradients and use them to detect edges! - - ===================== ============================================== - - .. |SobelDerivatives| image:: images/imgtrans/Sobel_Derivatives_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |LaplaceOperator| **Title:** :ref:`laplace_operator` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn about the *Laplace* operator and how to detect edges with it. - - ===================== ============================================== - - .. |LaplaceOperator| image:: images/imgtrans/Laplace_Operator_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |CannyDetector| **Title:** :ref:`canny_detector` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn a sophisticated alternative to detect edges. - - ===================== ============================================== - - .. |CannyDetector| image:: images/imgtrans/Canny_Detector_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |HoughLines| **Title:** :ref:`hough_lines` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to detect lines - - ===================== ============================================== - - .. |HoughLines| image:: images/imgtrans/Hough_Lines_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |HoughCircle| **Title:** :ref:`hough_circle` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to detect circles - - ===================== ============================================== - - .. |HoughCircle| image:: images/imgtrans/Hough_Circle_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |Remap| **Title:** :ref:`remap` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to manipulate pixels locations - - ===================== ============================================== - - .. |Remap| image:: images/imgtrans/Remap_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |WarpAffine| **Title:** :ref:`warp_affine` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to rotate, translate and scale our images - - ===================== ============================================== - - .. |WarpAffine| image:: images/imgtrans/Warp_Affine_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |HistEqualization| **Title:** :ref:`histogram_equalization` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to improve the contrast in our images - - ===================== ============================================== - - .. |HistEqualization| image:: images/histograms/Histogram_Equalization_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |HistCalculation| **Title:** :ref:`histogram_calculation` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to create and generate histograms - - ===================== ============================================== - - .. |HistCalculation| image:: images/histograms/Histogram_Calculation_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |HistComparison| **Title:** :ref:`histogram_comparison` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn to calculate metrics between histograms - - ===================== ============================================== - - .. |HistComparison| image:: images/histograms/Histogram_Comparison_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |BackProjection| **Title:** :ref:`back_projection` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to use histograms to find similar objects in images - - ===================== ============================================== - - .. |BackProjection| image:: images/histograms/Back_Projection_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |TemplateMatching| **Title:** :ref:`template_matching` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to match templates in an image - - ===================== ============================================== - - .. |TemplateMatching| image:: images/histograms/Template_Matching_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |FindContours| **Title:** :ref:`find_contours` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to find contours of objects in our image - - ===================== ============================================== - - .. |FindContours| image:: images/shapedescriptors/Find_Contours_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |Hull| **Title:** :ref:`hull` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to get hull contours and draw them! - - ===================== ============================================== - - .. |Hull| image:: images/shapedescriptors/Hull_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |BRC| **Title:** :ref:`bounding_rects_circles` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to obtain bounding boxes and circles for our contours. - - ===================== ============================================== - - .. |BRC| image:: images/shapedescriptors/Bounding_Rects_Circles_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - - ===================== ============================================== - |BRE| **Title:** :ref:`bounding_rotated_ellipses` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to obtain rotated bounding boxes and ellipses for our contours. - - ===================== ============================================== - - .. |BRE| image:: images/shapedescriptors/Bounding_Rotated_Ellipses_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - - ===================== ============================================== - |MU| **Title:** :ref:`moments` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn to calculate the moments of an image - - ===================== ============================================== - - .. |MU| image:: images/shapedescriptors/Moments_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - - -+ - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - - ===================== ============================================== - |PPT| **Title:** :ref:`point_polygon_test` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Where we learn how to calculate distances from the image to contours - - ===================== ============================================== - - .. |PPT| image:: images/shapedescriptors/Point_Polygon_Test_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. toctree:: - :hidden: - - ../gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter - ../erosion_dilatation/erosion_dilatation - ../opening_closing_hats/opening_closing_hats - ../pyramids/pyramids - ../threshold/threshold - ../imgtrans/filter_2d/filter_2d - ../imgtrans/copyMakeBorder/copyMakeBorder - ../imgtrans/sobel_derivatives/sobel_derivatives - ../imgtrans/laplace_operator/laplace_operator - ../imgtrans/canny_detector/canny_detector - ../imgtrans/hough_lines/hough_lines - ../imgtrans/hough_circle/hough_circle - ../imgtrans/remap/remap - ../imgtrans/warp_affine/warp_affine - ../histograms/histogram_equalization/histogram_equalization - ../histograms/histogram_calculation/histogram_calculation - ../histograms/histogram_comparison/histogram_comparison - ../histograms/back_projection/back_projection - ../histograms/template_matching/template_matching - ../shapedescriptors/find_contours/find_contours - ../shapedescriptors/hull/hull - ../shapedescriptors/bounding_rects_circles/bounding_rects_circles - ../shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses - ../shapedescriptors/moments/moments - ../shapedescriptors/point_polygon_test/point_polygon_test diff --git a/doc/tutorials/imgproc/threshold/threshold.rst b/doc/tutorials/imgproc/threshold/threshold.rst deleted file mode 100644 index 2395d387ea..0000000000 --- a/doc/tutorials/imgproc/threshold/threshold.rst +++ /dev/null @@ -1,310 +0,0 @@ -.. _Basic_Threshold: - -Basic Thresholding Operations -******************************* - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Perform basic thresholding operations using OpenCV function :threshold:`threshold <>` - - -Cool Theory -============ - -.. note:: - The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. - -What is Thresholding? ------------------------ - -* The simplest segmentation method - -* Application example: Separate out regions of an image corresponding to objects which we want to analyze. This separation is based on the variation of intensity between the object pixels and the background pixels. - -* To differentiate the pixels we are interested in from the rest (which will eventually be rejected), we perform a comparison of each pixel intensity value with respect to a *threshold* (determined according to the problem to solve). - -* Once we have separated properly the important pixels, we can set them with a determined value to identify them (i.e. we can assign them a value of :math:`0` (black), :math:`255` (white) or any value that suits your needs). - - .. image:: images/Threshold_Tutorial_Theory_Example.jpg - :alt: Threshold simple example - :align: center - -Types of Thresholding ------------------------ - -* OpenCV offers the function :threshold:`threshold <>` to perform thresholding operations. - -* We can effectuate :math:`5` types of Thresholding operations with this function. We will explain them in the following subsections. - -* To illustrate how these thresholding processes work, let's consider that we have a source image with pixels with intensity values :math:`src(x,y)`. The plot below depicts this. The horizontal blue line represents the threshold :math:`thresh` (fixed). - - .. image:: images/Threshold_Tutorial_Theory_Base_Figure.png - :alt: Threshold Binary - :align: center - -Threshold Binary -^^^^^^^^^^^^^^^^^ - -* This thresholding operation can be expressed as: - - .. math:: - - \texttt{dst} (x,y) = \fork{\texttt{maxVal}}{if $\texttt{src}(x,y) > \texttt{thresh}$}{0}{otherwise} - -* So, if the intensity of the pixel :math:`src(x,y)` is higher than :math:`thresh`, then the new pixel intensity is set to a :math:`MaxVal`. Otherwise, the pixels are set to :math:`0`. - - .. image:: images/Threshold_Tutorial_Theory_Binary.png - :alt: Threshold Binary - :align: center - - -Threshold Binary, Inverted -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -* This thresholding operation can be expressed as: - - .. math:: - - \texttt{dst} (x,y) = \fork{0}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{maxVal}}{otherwise} - -* If the intensity of the pixel :math:`src(x,y)` is higher than :math:`thresh`, then the new pixel intensity is set to a :math:`0`. Otherwise, it is set to :math:`MaxVal`. - - .. image:: images/Threshold_Tutorial_Theory_Binary_Inverted.png - :alt: Threshold Binary Inverted - :align: center - -Truncate -^^^^^^^^^ - -* This thresholding operation can be expressed as: - - .. math:: - - \texttt{dst} (x,y) = \fork{\texttt{threshold}}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{src}(x,y)}{otherwise} - -* The maximum intensity value for the pixels is :math:`thresh`, if :math:`src(x,y)` is greater, then its value is *truncated*. See figure below: - - .. image:: images/Threshold_Tutorial_Theory_Truncate.png - :alt: Threshold Truncate - :align: center - - - -Threshold to Zero -^^^^^^^^^^^^^^^^^^ - -* This operation can be expressed as: - - .. math:: - - \texttt{dst} (x,y) = \fork{\texttt{src}(x,y)}{if $\texttt{src}(x,y) > \texttt{thresh}$}{0}{otherwise} - -* If :math:`src(x,y)` is lower than :math:`thresh`, the new pixel value will be set to :math:`0`. - - .. image:: images/Threshold_Tutorial_Theory_Zero.png - :alt: Threshold Zero - :align: center - - -Threshold to Zero, Inverted -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -* This operation can be expressed as: - - .. math:: - - \texttt{dst} (x,y) = \fork{0}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{src}(x,y)}{otherwise} - -* If :math:`src(x,y)` is greater than :math:`thresh`, the new pixel value will be set to :math:`0`. - - .. image:: images/Threshold_Tutorial_Theory_Zero_Inverted.png - :alt: Threshold Zero Inverted - :align: center - - -Code -====== - -The tutorial code's is shown lines below. You can also download it from `here `_ - -.. code-block:: cpp - - #include "opencv2/imgproc.hpp" - #include "opencv2/highgui.hpp" - #include - #include - - using namespace cv; - - /// Global variables - - int threshold_value = 0; - int threshold_type = 3;; - int const max_value = 255; - int const max_type = 4; - int const max_BINARY_value = 255; - - Mat src, src_gray, dst; - char* window_name = "Threshold Demo"; - - char* trackbar_type = "Type: \n 0: Binary \n 1: Binary Inverted \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; - char* trackbar_value = "Value"; - - /// Function headers - void Threshold_Demo( int, void* ); - - /* - * @function main - */ - int main( int argc, char** argv ) - { - /// Load an image - src = imread( argv[1], 1 ); - - /// Convert the image to Gray - cvtColor( src, src_gray, COLOR_RGB2GRAY ); - - /// Create a window to display results - namedWindow( window_name, WINDOW_AUTOSIZE ); - - /// Create Trackbar to choose type of Threshold - createTrackbar( trackbar_type, - window_name, &threshold_type, - max_type, Threshold_Demo ); - - createTrackbar( trackbar_value, - window_name, &threshold_value, - max_value, Threshold_Demo ); - - /// Call the function to initialize - Threshold_Demo( 0, 0 ); - - /// Wait until user finishes program - while(true) - { - int c; - c = waitKey( 20 ); - if( (char)c == 27 ) - { break; } - } - - } - - - /* - * @function Threshold_Demo - */ - void Threshold_Demo( int, void* ) - { - /* 0: Binary - 1: Binary Inverted - 2: Threshold Truncated - 3: Threshold to Zero - 4: Threshold to Zero Inverted - */ - - threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type ); - - imshow( window_name, dst ); - } - - - -Explanation -============= - - -#. Let's check the general structure of the program: - - * Load an image. If it is RGB we convert it to Grayscale. For this, remember that we can use the function :cvt_color:`cvtColor <>`: - - .. code-block:: cpp - - src = imread( argv[1], 1 ); - - /// Convert the image to Gray - cvtColor( src, src_gray, COLOR_RGB2GRAY ); - - - * Create a window to display the result - - .. code-block:: cpp - - namedWindow( window_name, WINDOW_AUTOSIZE ); - - * Create :math:`2` trackbars for the user to enter user input: - - * **Type of thresholding**: Binary, To Zero, etc... - * **Threshold value** - - .. code-block:: cpp - - createTrackbar( trackbar_type, - window_name, &threshold_type, - max_type, Threshold_Demo ); - - createTrackbar( trackbar_value, - window_name, &threshold_value, - max_value, Threshold_Demo ); - - * Wait until the user enters the threshold value, the type of thresholding (or until the program exits) - - * Whenever the user changes the value of any of the Trackbars, the function *Threshold_Demo* is called: - - .. code-block:: cpp - - /* - * @function Threshold_Demo - */ - void Threshold_Demo( int, void* ) - { - /* 0: Binary - 1: Binary Inverted - 2: Threshold Truncated - 3: Threshold to Zero - 4: Threshold to Zero Inverted - */ - - threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type ); - - imshow( window_name, dst ); - } - - As you can see, the function :threshold:`threshold <>` is invoked. We give :math:`5` parameters: - - * *src_gray*: Our input image - * *dst*: Destination (output) image - * *threshold_value*: The :math:`thresh` value with respect to which the thresholding operation is made - * *max_BINARY_value*: The value used with the Binary thresholding operations (to set the chosen pixels) - * *threshold_type*: One of the :math:`5` thresholding operations. They are listed in the comment section of the function above. - - - -Results -======== - -#. After compiling this program, run it giving a path to an image as argument. For instance, for an input image as: - - - .. image:: images/Threshold_Tutorial_Original_Image.jpg - :alt: Threshold Original Image - :align: center - -#. First, we try to threshold our image with a *binary threhold inverted*. We expect that the pixels brighter than the :math:`thresh` will turn dark, which is what actually happens, as we can see in the snapshot below (notice from the original image, that the doggie's tongue and eyes are particularly bright in comparison with the image, this is reflected in the output image). - - - .. image:: images/Threshold_Tutorial_Result_Binary_Inverted.jpg - :alt: Threshold Result Binary Inverted - :align: center - - -#. Now we try with the *threshold to zero*. With this, we expect that the darkest pixels (below the threshold) will become completely black, whereas the pixels with value greater than the threshold will keep its original value. This is verified by the following snapshot of the output image: - - .. image:: images/Threshold_Tutorial_Result_Zero.jpg - :alt: Threshold Result Zero - :align: center diff --git a/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst b/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst deleted file mode 100644 index a70a98d52a..0000000000 --- a/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst +++ /dev/null @@ -1,341 +0,0 @@ - -.. _O4A_SDK: - - -OpenCV4Android SDK -****************** - -This tutorial was designed to help you with installation and configuration of OpenCV4Android SDK. - -This guide was written with MS Windows 7 in mind, though it should work with GNU Linux and Apple -Mac OS as well. - -This tutorial assumes you have the following software installed and configured: - -* JDK - -* Android SDK and NDK - -* Eclipse IDE - -* ADT and CDT plugins for Eclipse - - .. - -If you need help with anything of the above, you may refer to our :ref:`android_dev_intro` guide. - -If you encounter any error after thoroughly following these steps, feel free to contact us via -`OpenCV4Android `_ discussion group or -OpenCV `Q&A forum `_. We'll do our best to help you out. - -Tegra Android Development Pack users -==================================== - -You may have used `Tegra Android Development Pack `_ -(**TADP**) released by **NVIDIA** for Android development environment setup. - -Beside Android development tools the TADP 2.0 includes OpenCV4Android SDK, so it can be already -installed in your system and you can skip to :ref:`Running_OpenCV_Samples` section of this tutorial. - -More details regarding TADP can be found in the :ref:`android_dev_intro` guide. - -General info -============ - -OpenCV4Android SDK package enables development of Android applications with use of OpenCV library. - -The structure of package contents looks as follows: - -:: - - OpenCV-2.4.9-android-sdk - |_ apk - | |_ OpenCV_2.4.9_binary_pack_armv7a.apk - | |_ OpenCV_2.4.9_Manager_2.18_XXX.apk - | - |_ doc - |_ samples - |_ sdk - | |_ etc - | |_ java - | |_ native - | |_ 3rdparty - | |_ jni - | |_ libs - | |_ armeabi - | |_ armeabi-v7a - | |_ x86 - | - |_ LICENSE - |_ README.android - -* :file:`sdk` folder contains OpenCV API and libraries for Android: - -* :file:`sdk/java` folder contains an Android library Eclipse project providing OpenCV Java API that - can be imported into developer's workspace; - -* :file:`sdk/native` folder contains OpenCV C++ headers (for JNI code) and native Android libraries - (\*\.so and \*\.a) for ARM-v5, ARM-v7a and x86 architectures; - -* :file:`sdk/etc` folder contains Haar and LBP cascades distributed with OpenCV. - -* :file:`apk` folder contains Android packages that should be installed on the target Android device - to enable OpenCV library access via OpenCV Manager API (see details below). - - On production devices that have access to Google Play Market (and Internet) these packages will be - installed from Market on the first start of an application using OpenCV Manager API. - But devkits without Market or Internet connection require this packages to be installed manually. - Install the `Manager.apk` and optional `binary_pack.apk` if it needed. - See :ref:`manager_selection` for details. - - .. note:: Installation from Internet is the preferable way since OpenCV team may publish updated - versions of this packages on the Market. - -* :file:`samples` folder contains sample applications projects and their prebuilt packages (APK). - Import them into Eclipse workspace (like described below) and browse the code to learn possible - ways of OpenCV use on Android. - -* :file:`doc` folder contains various OpenCV documentation in PDF format. - It's also available online at http://docs.opencv.org. - - .. note:: The most recent docs (nightly build) are at http://docs.opencv.org/2.4. - Generally, it's more up-to-date, but can refer to not-yet-released functionality. - -.. TODO: I'm not sure that this is the best place to talk about OpenCV Manager - -Starting from version 2.4.3 `OpenCV4Android SDK` uses `OpenCV Manager` API for library -initialization. `OpenCV Manager` is an Android service based solution providing the following -benefits for OpenCV applications developers: - -* Compact apk-size, since all applications use the same binaries from Manager and do not store - native libs within themselves; - -* Hardware specific optimizations are automatically enabled on all supported platforms; - -* Automatic updates and bug fixes; - -* Trusted OpenCV library source. All packages with OpenCV are published on Google Play; - - .. - -For additional information on OpenCV Manager see the: - -* |OpenCV4Android_Slides|_ - -* |OpenCV4Android_Reference|_ - - .. - -.. |OpenCV4Android_Slides| replace:: Slides -.. _OpenCV4Android_Slides: https://docs.google.com/a/itseez.com/presentation/d/1EO_1kijgBg_BsjNp2ymk-aarg-0K279_1VZRcPplSuk/present#slide=id.p -.. |OpenCV4Android_Reference| replace:: Reference Manual -.. _OpenCV4Android_Reference: http://docs.opencv.org/android/refman.html - -Manual OpenCV4Android SDK setup -=============================== - -Get the OpenCV4Android SDK --------------------------- - -#. Go to the `OpenCV download page on SourceForge `_ - and download the latest available version. Currently it's |opencv_android_bin_pack_url|_. - -#. Create a new folder for Android with OpenCV development. For this tutorial we have unpacked - OpenCV SDK to the :file:`C:\\Work\\OpenCV4Android\\` directory. - - .. note:: Better to use a path without spaces in it. Otherwise you may have problems with :command:`ndk-build`. - -#. Unpack the SDK archive into the chosen directory. - - You can unpack it using any popular archiver (e.g with |seven_zip|_): - - .. image:: images/android_package_7zip.png - :alt: Exploring OpenCV package with 7-Zip - :align: center - - On Unix you can use the following command: - - .. code-block:: bash - - unzip ~/Downloads/OpenCV-2.4.9-android-sdk.zip - -.. |opencv_android_bin_pack| replace:: :file:`OpenCV-2.4.9-android-sdk.zip` -.. _opencv_android_bin_pack_url: http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.4.9/OpenCV-2.4.9-android-sdk.zip/download -.. |opencv_android_bin_pack_url| replace:: |opencv_android_bin_pack| -.. |seven_zip| replace:: 7-Zip -.. _seven_zip: http://www.7-zip.org/ - -Import OpenCV library and samples to the Eclipse ------------------------------------------------- - -#. Start Eclipse and choose your workspace location. - - We recommend to start working with OpenCV for Android from a new clean workspace. A new Eclipse - workspace can for example be created in the folder where you have unpacked OpenCV4Android SDK package: - - .. image:: images/eclipse_1_choose_workspace.png - :alt: Choosing C:\Work\android-opencv\ as workspace location - :align: center - -#. Import OpenCV library and samples into workspace. - - OpenCV library is packed as a ready-for-use `Android Library Project - `_. - You can simply reference it in your projects. - - Each sample included into the |opencv_android_bin_pack| is a regular Android project that already - references OpenCV library. Follow the steps below to import OpenCV and samples into the workspace: - - .. note:: OpenCV samples are indeed **dependent** on OpenCV library project so don't forget to import it to your workspace as well. - - * Right click on the :guilabel:`Package Explorer` window and choose :guilabel:`Import...` option - from the context menu: - - .. image:: images/eclipse_5_import_command.png - :alt: Select Import... from context menu - :align: center - - * In the main panel select :menuselection:`General --> Existing Projects into Workspace` and - press :guilabel:`Next` button: - - .. image:: images/eclipse_6_import_existing_projects.png - :alt: General > Existing Projects into Workspace - :align: center - - * In the :guilabel:`Select root directory` field locate your OpenCV package folder. Eclipse - should automatically locate OpenCV library and samples: - - .. image:: images/eclipse_7_select_projects.png - :alt: Locate OpenCV library and samples - :align: center - - * Click :guilabel:`Finish` button to complete the import operation. - - After clicking :guilabel:`Finish` button Eclipse will load all selected projects into workspace, - and you have to wait some time while it is building OpenCV samples. Just give a minute to - Eclipse to complete initialization. - - .. warning :: After the initial import, on a non-Windows (Linux and Mac OS) operating system Eclipse - will still show build errors for applications with native C++ code. To resolve the - issues, please do the following: - - Open :guilabel:`Project Properties -> C/C++ Build`, and replace "Build command" text - to ``"${NDKROOT}/ndk-build"`` (remove .cmd at the end). - - .. note :: In some cases the build errors don't disappear, then try the following actions: - - * right click on ``OpenCV Library`` project -> :guilabel:`Android Tools -> Fix Project Properties`, - then menu :guilabel:`Project -> Clean... -> Clean all` - * right click on the project with errors -> :guilabel:`Properties -> Android`, make sure the - ``Target`` is selected and is ``Android 3.0`` or higher - * check the build errors in the :guilabel:`Problems` view window and try to resolve them by yourselves - - .. image:: images/eclipse_cdt_cfg4.png - :alt: Configure CDT - :align: center - - Once Eclipse completes build you will have the clean workspace without any build errors: - - .. image:: images/eclipse_10_crystal_clean.png - :alt: OpenCV package imported into Eclipse - :align: center - -.. _Running_OpenCV_Samples: - -Running OpenCV Samples ----------------------- - -At this point you should be able to build and run the samples. Keep in mind, that -``face-detection`` and ``Tutorial 2 - Mixed Processing`` include some native code and -require Android NDK and NDK/CDT plugin for Eclipse to build working applications. If you haven't -installed these tools, see the corresponding section of :ref:`Android_Dev_Intro`. - -.. warning:: Please consider that some samples use Android Java Camera API, which is accessible - with an AVD. But most of samples use OpenCV Native Camera which **may not work** with - an emulator. - -.. note:: Recent *Android SDK tools, revision 19+* can run ARM v7a OS images but they available not - for all Android versions. - -Well, running samples from Eclipse is very simple: - -* Connect your device with :command:`adb` tool from Android SDK or create an emulator with camera support. - - * See `Managing Virtual Devices - `_ document for help with Android Emulator. - * See `Using Hardware Devices - `_ for help with real devices (not emulators). - - -* Select project you want to start in :guilabel:`Package Explorer` and just press :kbd:`Ctrl + F11` - or select option :menuselection:`Run --> Run` from the main menu, or click :guilabel:`Run` button on the toolbar. - - .. note:: Android Emulator can take several minutes to start. So, please, be patient. - -* On the first run Eclipse will ask you about the running mode for your application: - - .. image:: images/eclipse_11_run_as.png - :alt: Run sample as Android Application - :align: center - -* Select the :guilabel:`Android Application` option and click :guilabel:`OK` button. Eclipse will install and run the sample. - - Chances are that on the first launch you will not have the `OpenCV Manager `_ package installed. - In this case you will see the following message: - - .. image:: images/android_emulator_opencv_manager_fail.png - :alt: You will see this message if you have no OpenCV Manager installed - :align: center - - To get rid of the message you will need to install `OpenCV Manager` and the appropriate `OpenCV binary pack`. - Simply tap :menuselection:`Yes` if you have *Google Play Market* installed on your device/emulator. It will redirect you to the corresponding page on *Google Play Market*. - - If you have no access to the *Market*, which is often the case with emulators - you will need to install the packages from OpenCV4Android SDK folder manually. See :ref:`manager_selection` for details. - - .. code-block:: sh - :linenos: - - /platform-tools/adb install /apk/OpenCV_2.4.9_Manager_2.18_armv7a-neon.apk - - .. note:: ``armeabi``, ``armv7a-neon``, ``arm7a-neon-android8``, ``mips`` and ``x86`` stand for - platform targets: - - * ``armeabi`` is for ARM v5 and ARM v6 architectures with Android API 8+, - - * ``armv7a-neon`` is for NEON-optimized ARM v7 with Android API 9+, - - * ``arm7a-neon-android8`` is for NEON-optimized ARM v7 with Android API 8, - - * ``mips`` is for MIPS architecture with Android API 9+, - - * ``x86`` is for Intel x86 CPUs with Android API 9+. - - If using hardware device for testing/debugging, run the following command to learn - its CPU architecture: - - .. code-block:: sh - - adb shell getprop ro.product.cpu.abi - - If you're using an AVD emulator, go :menuselection:`Window > AVD Manager` to see the - list of availible devices. Click :menuselection:`Edit` in the context menu of the - selected device. In the window, which then pop-ups, find the CPU field. - - You may also see section :ref:`manager_selection` for details. - - - When done, you will be able to run OpenCV samples on your device/emulator seamlessly. - -* Here is ``Sample - image-manipulations`` sample, running on top of stock camera-preview of the emulator. - - .. image:: images/emulator_canny.png - :alt: 'Sample - image-manipulations' running Canny - :align: center - - -What's next -=========== - -Now, when you have your instance of OpenCV4Adroid SDK set up and configured, -you may want to proceed to using OpenCV in your own application. -You can learn how to do that in a separate :ref:`dev_with_OCV_on_Android` tutorial. diff --git a/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst b/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst deleted file mode 100644 index 8c470925ff..0000000000 --- a/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst +++ /dev/null @@ -1,655 +0,0 @@ - -.. _Android_Dev_Intro: - - -Introduction into Android Development -************************************* - -This guide was designed to help you in learning Android development basics and setting up your -working environment quickly. It was written with Windows 7 in mind, though it would work with Linux -(Ubuntu), Mac OS X and any other OS supported by Android SDK. - -If you encounter any error after thoroughly following these steps, feel free to contact us via -`OpenCV4Android `_ discussion group or -OpenCV `Q&A forum `_. We'll do our best to help you out. - -Preface -======= -Android is a Linux-based, open source mobile operating system developed by Open Handset Alliance -led by Google. See the `Android home site `_ for general details. - -Development for Android significantly differs from development for other platforms. -So before starting programming for Android we recommend you make sure that you are familiar with the -following key topis: - -#. `Java `_ programming language that is - the primary development technology for Android OS. Also, you can find - `Oracle docs on Java `_ useful. -#. `Java Native Interface (JNI) `_ that is a - technology of running native code in Java virtual machine. Also, you can find - `Oracle docs on JNI `_ useful. -#. `Android Activity `_ - and its lifecycle, that is an essential Android API class. -#. OpenCV development will certainly require some knowlege of the - `Android Camera `_ specifics. - - -Quick environment setup for Android development -=============================================== - -If you are making a clean environment install, then you can try `Tegra Android Development Pack `_ -(**TADP**) released by **NVIDIA**. - - .. note:: Starting the *version 2.0* the TADP package includes *OpenCV for Tegra* SDK that is a regular *OpenCV4Android SDK* extended with Tegra-specific stuff. - -When unpacked, TADP will cover all of the environment setup automatically and you can skip the rest of the guide. - -If you are a beginner in Android development then we also recommend you to start with TADP. - - .. note:: *NVIDIA*\ 's Tegra Android Development Pack includes some special features for - |Nvidia_Tegra_Platform|_ but its use is not limited to *Tegra* devices only. - -* You need at least *1.6 Gb* free disk space for the install. - -* TADP will download Android SDK platforms and Android NDK from Google's server, so Internet - connection is required for the installation. - -* TADP may ask you to flash your development kit at the end of installation process. Just skip - this step if you have no |Tegra_Development_Kit|_\ . - -* (``UNIX``) TADP will ask you for *root* in the middle of installation, so you need to be a - member of *sudo* group. - - .. - -.. |Nvidia_Tegra_Platform| replace:: *NVIDIA*\ ’s Tegra platform -.. _Nvidia_Tegra_Platform: http://www.nvidia.com/object/tegra-3-processor.html -.. |Tegra_Development_Kit| replace:: Tegra Development Kit -.. _Tegra_Development_Kit: http://developer.nvidia.com/mobile/tegra-hardware-sales-inquiries - -.. _Android_Environment_Setup_Lite: - - -Manual environment setup for Android development -================================================ - -Development in Java -------------------- - -You need the following software to be installed in order to develop for Android in Java: - -#. **Sun JDK 6** (Sun JDK 7 is also possible) - - Visit `Java SE Downloads page `_ - and download an installer for your OS. - - Here is a detailed :abbr:`JDK (Java Development Kit)` - `installation guide `_ - for Ubuntu and Mac OS (only JDK sections are applicable for OpenCV) - - .. note:: OpenJDK is not suitable for Android development, since Android SDK supports only Sun JDK. - If you use Ubuntu, after installation of Sun JDK you should run the following command to set - Sun java environment: - - .. code-block:: bash - - sudo update-java-alternatives --set java-6-sun - - .. TODO: Add a note on Sun/Oracle Java installation on Ubuntu 12. - -#. **Android SDK** - - Get the latest ``Android SDK`` from http://developer.android.com/sdk/index.html - - Here is Google's `install guide `_ for the SDK. - - .. note:: You can choose downloading **ADT Bundle package** that in addition to Android SDK Tools includes - Eclipse + ADT + NDK/CDT plugins, Android Platform-tools, the latest Android platform and the latest - Android system image for the emulator - this is the best choice for those who is setting up Android - development environment the first time! - - .. note:: If you are running x64 version of Ubuntu Linux, then you need ia32 shared libraries - for use on amd64 and ia64 systems to be installed. You can install them with the - following command: - - .. code-block:: bash - - sudo apt-get install ia32-libs - - For Red Hat based systems the following command might be helpful: - - .. code-block:: bash - - sudo yum install libXtst.i386 - -#. **Android SDK components** - - You need the following SDK components to be installed: - - * *Android SDK Tools, revision 20* or newer. - - Older revisions should also work, but they are not recommended. - - * *SDK Platform Android 3.0* (``API 11``). - - The minimal platform supported by OpenCV Java API is **Android 2.2** (``API 8``). This is also - the minimum API Level required for the provided samples to run. - See the ```` tag in their **AndroidManifest.xml** files. - But for successful compilation the **target** platform should be set to Android 3.0 (API 11) or higher. It will not prevent them from running on Android 2.2. - - .. image:: images/android_sdk_and_avd_manager.png - :alt: Android SDK Manager - :align: center - - See `Adding Platforms and Packages `_ - for help with installing/updating SDK components. - -#. **Eclipse IDE** - - Check the `Android SDK System Requirements `_ - document for a list of Eclipse versions that are compatible with the Android SDK. - For OpenCV 2.4.x we recommend **Eclipse 3.7 (Indigo)** or **Eclipse 4.2 (Juno)**. They work well for - OpenCV under both Windows and Linux. - - If you have no Eclipse installed, you can get it from the `official site `_. - -#. **ADT plugin for Eclipse** - - These instructions are copied from - `Android Developers site `_, - check it out in case of any ADT-related problem. - - Assuming that you have Eclipse IDE installed, as described above, follow these steps to download - and install the ADT plugin: - - #. Start Eclipse, then select :menuselection:`Help --> Install New Software...` - #. Click :guilabel:`Add` (in the top-right corner). - #. In the :guilabel:`Add Repository` dialog that appears, enter "ADT Plugin" for the Name and the - following URL for the Location: - - https://dl-ssl.google.com/android/eclipse/ - - #. Click :guilabel:`OK` - - .. note:: If you have trouble acquiring the plugin, try using "http" in the Location URL, - instead of "https" (https is preferred for security reasons). - - #. In the :guilabel:`Available Software` dialog, select the checkbox next to - :guilabel:`Developer Tools` and click :guilabel:`Next`. - #. In the next window, you'll see a list of the tools to be downloaded. Click :guilabel:`Next`. - - .. note:: If you also plan to develop native C++ code with Android NDK don't forget to - enable `NDK Plugins` installations as well. - - .. image:: images/eclipse_inst_adt.png - :alt: ADT installation - :align: center - - - #. Read and accept the license agreements, then click :guilabel:`Finish`. - - .. note:: If you get a security warning saying that the authenticity or validity of the software - can't be established, click :guilabel:`OK`. - - #. When the installation completes, restart Eclipse. - -Native development in C++ -------------------------- - -You need the following software to be installed in order to develop for Android in C++: - -#. **Android NDK** - - To compile C++ code for Android platform you need ``Android Native Development Kit`` (*NDK*). - - You can get the latest version of NDK from the - `download page `_. - To install Android NDK just extract the archive to some folder on your computer. Here are - `installation instructions `_. - - .. note:: Before start you can read official Android NDK documentation which is in the Android - NDK archive, in the folder :file:`docs/`. - The main article about using Android NDK build system is in the :file:`ANDROID-MK.html` file. - Some additional information you can find in - the :file:`APPLICATION-MK.html`, :file:`NDK-BUILD.html` files, - and :file:`CPU-ARM-NEON.html`, :file:`CPLUSPLUS-SUPPORT.html`, :file:`PREBUILTS.html`. - -#. **CDT plugin for Eclipse** - - If you selected for installation the ``NDK plugins`` component of Eclipse ADT plugin (see the picture above) your Eclipse IDE - should already have ``CDT plugin`` (that means ``C/C++ Development Tooling``). - There are several possible ways to integrate compilation of C++ code by Android NDK into Eclipse - compilation process. We recommend the approach based on Eclipse - :abbr:`CDT(C/C++ Development Tooling)` Builder. - - -Android application structure -============================= - -Usually source code of an Android application has the following structure: - -+ :file:`root folder of the project/` - - - :file:`jni/` - - - :file:`libs/` - - - :file:`res/` - - - :file:`src/` - - - :file:`AndroidManifest.xml` - - - :file:`project.properties` - - - :file:`... other files ...` - -Where: - -* the :file:`src` folder contains Java code of the application, - -* the :file:`res` folder contains resources of the application (images, xml files describing UI - layout, etc), - -* the :file:`libs` folder will contain native libraries after a successful build, - -* and the :file:`jni` folder contains C/C++ application source code and NDK's build scripts - :file:`Android.mk` and :file:`Application.mk` producing the native libraries, - -* :file:`AndroidManifest.xml` file presents essential information about application to the Android - system (name of the Application, name of main application's package, components of the - application, required permissions, etc). - - It can be created using Eclipse wizard or :command:`android` tool from Android SDK. - -* :file:`project.properties` is a text file containing information about target Android platform - and other build details. This file is generated by Eclipse or can be created with - :command:`android` tool included in Android SDK. - -.. note:: Both :file:`AndroidManifest.xml` and :file:`project.properties` files are required to - compile the C++ part of the application, since Android NDK build system relies on them. - If any of these files does not exist, compile the Java part of the project before the C++ part. - - -:file:`Android.mk` and :file:`Application.mk` scripts -================================================================== - -The script :file:`Android.mk` usually has the following structure: - -.. code-block:: make - :linenos: - - LOCAL_PATH := $(call my-dir) - - include $(CLEAR_VARS) - LOCAL_MODULE := - LOCAL_SRC_FILES := - := - ... - := - - include $(BUILD_SHARED_LIBRARY) - -This is the minimal file :file:`Android.mk`, which builds C++ source code of an Android application. -Note that the first two lines and the last line are mandatory for any :file:`Android.mk`. - -Usually the file :file:`Application.mk` is optional, but in case of project using OpenCV, when STL -and exceptions are used in C++, it also should be created. Example of the file :file:`Application.mk`: - -.. code-block:: make - :linenos: - - APP_STL := gnustl_static - APP_CPPFLAGS := -frtti -fexceptions - APP_ABI := all - -.. note:: We recommend setting ``APP_ABI := all`` for all targets. If you want to specify the - target explicitly, use ``armeabi`` for ARMv5/ARMv6, ``armeabi-v7a`` for ARMv7, ``x86`` - for Intel Atom or ``mips`` for MIPS. - - -.. _NDK_build_cli: - -Building application native part from command line -================================================== - -Here is the standard way to compile C++ part of an Android application: - -.. warning:: We strongly reccomend using ``cmd.exe`` (standard Windows console) instead of Cygwin on - **Windows**. Use the latter if only you're absolutely sure about, what you're doing. Cygwin - is not really supported and we are unlikely to help you in case you encounter some - problems with it. So, use it only if you're capable of handling the consequences yourself. - -#. Open console and go to the root folder of an Android application - - .. code-block:: bash - - cd / - -#. Run the following command - - .. code-block:: bash - - /ndk-build - - .. note:: On Windows we recommend to use ``ndk-build.cmd`` in standard Windows console (``cmd.exe``) - rather than the similar ``bash`` script in ``Cygwin`` shell. - - .. image:: images/ndk_build.png - :alt: NDK build - :align: center - -#. After executing this command the C++ part of the source code is compiled. - -After that the Java part of the application can be (re)compiled (using either *Eclipse* or *Ant* build tool). - -.. note:: Some parameters can be set for the :command:`ndk-build`: - - **Example 1**: Verbose compilation - - .. code-block:: bash - - /ndk-build V=1 - - **Example 2**: Rebuild all - - .. code-block:: bash - - /ndk-build -B - -.. _CDT_Builder: - -Building application native part from *Eclipse* (CDT Builder) -============================================================= - -There are several possible ways to integrate compilation of native C++ code by Android NDK into -Eclipse build process. We recommend the approach based on Eclipse -:abbr:`CDT(C/C++ Development Tooling)` Builder. - -.. important:: OpenCV for Android package since version 2.4.2 contains sample projects - pre-configured CDT Builders. For your own projects follow the steps below. - -#. Define the ``NDKROOT`` environment variable containing the path to Android NDK in your system - (e.g. ``"X:\\Apps\\android-ndk-r8"`` or ``"/opt/android-ndk-r8"``). - - **On Windows** an environment variable can be set via - :guilabel:`My Computer -> Properties -> Advanced -> Environment variables`. - On Windows 7 it's also possible to use `setx `_ command in a console session. - - **On Linux** and **MacOS** an environment variable can be set via appending a - ``"export VAR_NAME=VAR_VALUE"`` line to the :file:`"~/.bashrc"` file and logging off and then on. - - .. note:: It's also possible to define the ``NDKROOT`` environment variable within Eclipse IDE, - but it should be done for every new workspace you create. If you prefer this option better than setting system - environment variable, open Eclipse menu :guilabel:`Window -> Preferences -> C/C++ -> Build -> Environment`, - press the :guilabel:`Add...` button and set variable name to ``NDKROOT`` and value to local Android NDK path. - -#. After that you need to **restart Eclipse** to apply the changes. - -#. Open Eclipse and load the Android app project to configure. - -#. Add C/C++ Nature to the project via Eclipse menu :guilabel:`New -> Other -> C/C++ -> Convert to a C/C++ Project`. - - .. image:: images/eclipse_cdt_cfg1.png - :alt: Configure CDT - :align: center - - And: - - .. image:: images/eclipse_cdt_cfg2.png - :alt: Configure CDT - :align: center - -#. Select the project(s) to convert. Specify "Project type" = ``Makefile project``, - "Toolchains" = ``Other Toolchain``. - - .. image:: images/eclipse_cdt_cfg3.png - :alt: Configure CDT - :align: center - -#. Open :guilabel:`Project Properties -> C/C++ Build`, uncheck ``Use default build command``, - replace "Build command" text from ``"make"`` to - - ``"${NDKROOT}/ndk-build.cmd"`` on Windows, - - ``"${NDKROOT}/ndk-build"`` on Linux and MacOS. - - .. image:: images/eclipse_cdt_cfg4.png - :alt: Configure CDT - :align: center - -#. Go to :guilabel:`Behaviour` tab and change "Workbench build type" section like shown below: - - .. image:: images/eclipse_cdt_cfg5.png - :alt: Configure CDT - :align: center - -#. Press :guilabel:`OK` and make sure the ``ndk-build`` is successfully invoked when building the project. - - .. image:: images/eclipse_cdt_cfg6.png - :alt: Configure CDT - :align: center - -#. If you open your C++ source file in Eclipse editor, you'll see syntax error notifications. - They are not real errors, but additional CDT configuring is required. - - .. image:: images/eclipse_cdt_cfg7.png - :alt: Configure CDT - :align: center - -#. Open :guilabel:`Project Properties -> C/C++ General -> Paths and Symbols` and add the following - **Include** paths for **C++**: - - :: - - # for NDK r8 and prior: - ${NDKROOT}/platforms/android-9/arch-arm/usr/include - ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/include - ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/include - ${ProjDirPath}/../../sdk/native/jni/include - - :: - - # for NDK r8b and later: - ${NDKROOT}/platforms/android-9/arch-arm/usr/include - ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/include - ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include - ${ProjDirPath}/../../sdk/native/jni/include - - The last path should be changed to the correct absolute or relative path to OpenCV4Android SDK location. - - This should clear the syntax error notifications in Eclipse C++ editor. - - .. image:: images/eclipse_cdt_cfg8.png - :alt: Configure CDT - :align: center - - -Debugging and Testing -===================== -In this section we will give you some easy-to-follow instructions on how to set up an emulator or -hardware device for testing and debugging an Android project. - -AVD ---- -AVD (*Android Virtual Device*) is not probably the most convenient way to test an OpenCV-dependent -application, but sure the most uncomplicated one to configure. - -#. Assuming you already have *Android SDK* and *Eclipse IDE* installed, in Eclipse go - :guilabel:`Window -> AVD Manager`. - - .. TODO: how to start AVD Manager without Eclipse... - -#. Press the :guilabel:`New` button in :guilabel:`AVD Manager` window. -#. :guilabel:`Create new Android Virtual Device` window will let you select some properties for your - new device, like target API level, size of SD-card and other. - - .. image:: images/AVD_create.png - :alt: Configure builders - :align: center - -#. When you click the :guilabel:`Create AVD` button, your new AVD will be availible in :guilabel:`AVD Manager`. -#. Press :guilabel:`Start` to launch the device. Be aware that any AVD (a.k.a. Emulator) is usually - much slower than a hardware Android device, so it may take up to several minutes to start. -#. Go :guilabel:`Run -> Run/Debug` in Eclipse IDE to run your application in regular or debugging - mode. :guilabel:`Device Chooser` will let you choose among the running devices or to start a new one. - -Hardware Device ---------------- -If you have an Android device, you can use it to test and debug your applications. This way is more -authentic, though a little bit harder to set up. You need to make some actions for Windows and Linux -operating systems to be able to work with Android devices. No extra actions are required for Mac OS. -See detailed information on configuring hardware devices in subsections below. - -You may also consult the official -`Android Developers site instructions `_ -for more information. - -Windows host computer -^^^^^^^^^^^^^^^^^^^^^ - -#. Enable USB debugging on the Android device (via :guilabel:`Settings` menu). -#. Attach the Android device to your PC with a USB cable. -#. Go to :guilabel:`Start Menu` and **right-click** on :guilabel:`Computer`. - Select :guilabel:`Manage` in the context menu. You may be asked for Administrative permissions. -#. Select :guilabel:`Device Manager` in the left pane and find an unknown device in the list. - You may try unplugging it and then plugging back in order to check whether it's your exact - equipment appears in the list. - - .. image:: images/usb_device_connect_01.png - :alt: Unknown device - :align: center - -#. Try your luck installing `Google USB drivers` without any modifications: **right-click** on the - unknown device, select :guilabel:`Properties` menu item --> :guilabel:`Details` tab --> - :guilabel:`Update Driver` button. - - .. image:: images/usb_device_connect_05.png - :alt: Device properties - :align: center - -#. Select :guilabel:`Browse computer for driver software`. - - .. image:: images/usb_device_connect_06.png - :alt: Browse for driver - :align: center - -#. Specify the path to :file:`/extras/google/usb_driver/` folder. - - .. image:: images/usb_device_connect_07.png - :alt: Browse for driver - :align: center - -#. If you get the prompt to install unverified drivers and report about success - you've finished - with USB driver installation. - - .. image:: images/usb_device_connect_08.png - :alt: Install prompt - :align: center - - ` ` - .. FIXME: All such places should be replaced with something else! This is a bad separator. - - .. image:: images/usb_device_connect_09.png - :alt: Installed OK - :align: center - -#. Otherwise (getting the failure like shown below) follow the next steps. - - .. image:: images/usb_device_connect_12.png - :alt: No driver - :align: center - -#. Again **right-click** on the unknown device, select :guilabel:`Properties --> Details --> Hardware Ids` - and copy the line like ``USB\VID_XXXX&PID_XXXX&MI_XX``. - - .. image:: images/usb_device_connect_02.png - :alt: Device properties details - :align: center - -#. Now open file :file:`/extras/google/usb_driver/android_winusb.inf`. Select - either ``Google.NTx86`` or ``Google.NTamd64`` section depending on your host system architecture. - - .. image:: images/usb_device_connect_03.png - :alt: "android_winusb.inf" - :align: center - -#. There should be a record like existing ones for your device and you need to add one manually. - - .. image:: images/usb_device_connect_04.png - :alt: "android_winusb.inf" - :align: center - -#. Save the :file:`android_winusb.inf` file and try to install the USB driver again. - - .. image:: images/usb_device_connect_05.png - :alt: Device properties - :align: center - - ` ` - - .. image:: images/usb_device_connect_06.png - :alt: Browse for driver - :align: center - - ` ` - - .. image:: images/usb_device_connect_07.png - :alt: Browse for driver - :align: center - -#. This time installation should go successfully. - - .. image:: images/usb_device_connect_08.png - :alt: Install prompt - :align: center - - ` ` - - .. image:: images/usb_device_connect_09.png - :alt: Installed OK - :align: center - -#. And an unknown device is now recognized as an Android phone. - - .. image:: images/usb_device_connect_10.png - :alt: "Known" device - :align: center - -#. Successful device USB connection can be verified in console via ``adb devices`` command. - - .. image:: images/usb_device_connect_11.png - :alt: "adb devices" - :align: center - -#. Now, in Eclipse go :guilabel:`Run -> Run/Debug` to run your application in regular or debugging - mode. :guilabel:`Device Chooser` will let you choose among the devices. - -Linux host computer -^^^^^^^^^^^^^^^^^^^ -By default Linux doesn't recognize Android devices, but it's easy to fix this issue. On Ubuntu Linux -you have to create a new **/etc/udev/rules.d/51-android.rules** configuration file that contains -information about your Android device. You may find some Vendor ID's -`here `_ or execute :command:`lsusb` -command to view VendorID of plugged Android device. Here is an example of such file for LG device: - -.. code-block:: guess - - SUBSYSTEM=="usb", ATTR{idVendor}=="1004", MODE="0666", GROUP="plugdev" - -Then restart your adb server (even better to restart the system), plug in your Android device and -execute :command:`adb devices` command. You will see the list of attached devices: - -.. image:: images/usb_device_connect_ubuntu.png - :alt: List of attached devices - :align: center - -Mac OS host computer -^^^^^^^^^^^^^^^^^^^^ -No actions are required, just connect your device via USB and run ``adb devices`` to check connection. - -What's next -=========== - -Now, when you have your development environment set up and configured, you may want to proceed to -installing OpenCV4Android SDK. You can learn how to do that in a separate :ref:`O4A_SDK` tutorial. diff --git a/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst b/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst deleted file mode 100644 index 6fe8f6b941..0000000000 --- a/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.rst +++ /dev/null @@ -1,460 +0,0 @@ - -.. _dev_with_OCV_on_Android: - -Android Development with OpenCV -******************************* - -This tutorial has been created to help you use OpenCV library within your Android project. - -This guide was written with Windows 7 in mind, though it should work with any other OS supported by -OpenCV4Android SDK. - -This tutorial assumes you have the following installed and configured: - -* JDK - -* Android SDK and NDK - -* Eclipse IDE - -* ADT and CDT plugins for Eclipse - - .. - -If you need help with anything of the above, you may refer to our :ref:`android_dev_intro` guide. - -This tutorial also assumes you have OpenCV4Android SDK already installed on your development -machine and OpenCV Manager on your testing device correspondingly. If you need help with any of -these, you may consult our :ref:`O4A_SDK` tutorial. - -If you encounter any error after thoroughly following these steps, feel free to contact us via -`OpenCV4Android `_ discussion group or OpenCV -`Q&A forum `_ . We'll do our best to help you out. - - -Using OpenCV Library Within Your Android Project -================================================ - -In this section we will explain how to make some existing project to use OpenCV. -Starting with 2.4.2 release for Android, *OpenCV Manager* is used to provide apps with the best -available version of OpenCV. -You can get more information here: :ref:`Android_OpenCV_Manager` and in these -`slides `_. - - -Java ----- - -Application Development with Async Initialization -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Using async initialization is a **recommended** way for application development. It uses the OpenCV -Manager to access OpenCV libraries externally installed in the target system. - -#. Add OpenCV library project to your workspace. Use menu - :guilabel:`File -> Import -> Existing project in your workspace`. - - Press :guilabel:`Browse` button and locate OpenCV4Android SDK - (:file:`OpenCV-2.4.9-android-sdk/sdk`). - - .. image:: images/eclipse_opencv_dependency0.png - :alt: Add dependency from OpenCV library - :align: center - -#. In application project add a reference to the OpenCV Java SDK in - :guilabel:`Project -> Properties -> Android -> Library -> Add` select ``OpenCV Library - 2.4.9``. - - .. image:: images/eclipse_opencv_dependency1.png - :alt: Add dependency from OpenCV library - :align: center - -In most cases OpenCV Manager may be installed automatically from Google Play. For the case, when -Google Play is not available, i.e. emulator, developer board, etc, you can install it manually -using adb tool. See :ref:`manager_selection` for details. - -There is a very base code snippet implementing the async initialization. It shows basic principles. -See the "15-puzzle" OpenCV sample for details. - -.. code-block:: java - :linenos: - - public class Sample1Java extends Activity implements CvCameraViewListener { - - private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { - @Override - public void onManagerConnected(int status) { - switch (status) { - case LoaderCallbackInterface.SUCCESS: - { - Log.i(TAG, "OpenCV loaded successfully"); - mOpenCvCameraView.enableView(); - } break; - default: - { - super.onManagerConnected(status); - } break; - } - } - }; - - @Override - public void onResume() - { - super.onResume(); - OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_6, this, mLoaderCallback); - } - - ... - } - -It this case application works with OpenCV Manager in asynchronous fashion. ``OnManagerConnected`` -callback will be called in UI thread, when initialization finishes. Please note, that it is not -allowed to use OpenCV calls or load OpenCV-dependent native libs before invoking this callback. -Load your own native libraries that depend on OpenCV after the successful OpenCV initialization. -Default ``BaseLoaderCallback`` implementation treat application context as Activity and calls -``Activity.finish()`` method to exit in case of initialization failure. To override this behavior -you need to override ``finish()`` method of ``BaseLoaderCallback`` class and implement your own -finalization method. - - -Application Development with Static Initialization -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -According to this approach all OpenCV binaries are included into your application package. It is -designed mostly for development purposes. This approach is deprecated for the production code, -release package is recommended to communicate with OpenCV Manager via the async initialization -described above. - -#. Add the OpenCV library project to your workspace the same way as for the async initialization - above. Use menu :guilabel:`File -> Import -> Existing project in your workspace`, - press :guilabel:`Browse` button and select OpenCV SDK path - (:file:`OpenCV-2.4.9-android-sdk/sdk`). - - .. image:: images/eclipse_opencv_dependency0.png - :alt: Add dependency from OpenCV library - :align: center - -#. In the application project add a reference to the OpenCV4Android SDK in - :guilabel:`Project -> Properties -> Android -> Library -> Add` select ``OpenCV Library - 2.4.9``; - - .. image:: images/eclipse_opencv_dependency1.png - :alt: Add dependency from OpenCV library - :align: center - -#. If your application project **doesn't have a JNI part**, just copy the corresponding OpenCV - native libs from :file:`/sdk/native/libs/` to your - project directory to folder :file:`libs/`. - - In case of the application project **with a JNI part**, instead of manual libraries copying you - need to modify your ``Android.mk`` file: - add the following two code lines after the ``"include $(CLEAR_VARS)"`` and before - ``"include path_to_OpenCV-2.4.9-android-sdk/sdk/native/jni/OpenCV.mk"`` - - .. code-block:: make - :linenos: - - OPENCV_CAMERA_MODULES:=on - OPENCV_INSTALL_MODULES:=on - - The result should look like the following: - - .. code-block:: make - :linenos: - - include $(CLEAR_VARS) - - # OpenCV - OPENCV_CAMERA_MODULES:=on - OPENCV_INSTALL_MODULES:=on - include ../../sdk/native/jni/OpenCV.mk - - After that the OpenCV libraries will be copied to your application :file:`libs` folder during - the JNI build.v - - Eclipse will automatically include all the libraries from the :file:`libs` folder to the - application package (APK). - -#. The last step of enabling OpenCV in your application is Java initialization code before calling - OpenCV API. It can be done, for example, in the static section of the ``Activity`` class: - - .. code-block:: java - :linenos: - - static { - if (!OpenCVLoader.initDebug()) { - // Handle initialization error - } - } - - If you application includes other OpenCV-dependent native libraries you should load them - **after** OpenCV initialization: - - .. code-block:: java - :linenos: - - static { - if (!OpenCVLoader.initDebug()) { - // Handle initialization error - } else { - System.loadLibrary("my_jni_lib1"); - System.loadLibrary("my_jni_lib2"); - } - } - - -Native/C++ ----------- - -To build your own Android application, using OpenCV as native part, the following steps should be -taken: - -#. You can use an environment variable to specify the location of OpenCV package or just hardcode - absolute or relative path in the :file:`jni/Android.mk` of your projects. - -#. The file :file:`jni/Android.mk` should be written for the current application using the common - rules for this file. - - For detailed information see the Android NDK documentation from the Android NDK archive, in the - file :file:`/docs/ANDROID-MK.html`. - -#. The following line: - - .. code-block:: make - - include C:\Work\OpenCV4Android\OpenCV-2.4.9-android-sdk\sdk\native\jni\OpenCV.mk - - Should be inserted into the :file:`jni/Android.mk` file **after** this line: - - .. code-block:: make - - include $(CLEAR_VARS) - -#. Several variables can be used to customize OpenCV stuff, but you **don't need** to use them when - your application uses the `async initialization` via the `OpenCV Manager` API. - - .. note:: These variables should be set **before** the ``"include .../OpenCV.mk"`` line: - - .. code-block:: make - - OPENCV_INSTALL_MODULES:=on - - Copies necessary OpenCV dynamic libs to the project ``libs`` folder in order to include them - into the APK. - - .. code-block:: make - - OPENCV_CAMERA_MODULES:=off - - Skip native OpenCV camera related libs copying to the project ``libs`` folder. - - .. code-block:: make - - OPENCV_LIB_TYPE:=STATIC - - Perform static linking with OpenCV. By default dynamic link is used and the project JNI lib - depends on ``libopencv_java.so``. - -#. The file :file:`Application.mk` should exist and should contain lines: - - .. code-block:: make - - APP_STL := gnustl_static - APP_CPPFLAGS := -frtti -fexceptions - - Also, the line like this one: - - .. code-block:: make - - APP_ABI := armeabi-v7a - - Should specify the application target platforms. - - In some cases a linkage error (like ``"In function 'cv::toUtf16(std::basic_string<...>... - undefined reference to 'mbstowcs'"``) happens when building an application JNI library, - depending on OpenCV. The following line in the :file:`Application.mk` usually fixes it: - - .. code-block:: make - - APP_PLATFORM := android-9 - - -#. Either use :ref:`manual ` ``ndk-build`` invocation or - :ref:`setup Eclipse CDT Builder ` to build native JNI lib before (re)building the Java - part and creating an APK. - - -Hello OpenCV Sample -=================== - -Here are basic steps to guide you trough the process of creating a simple OpenCV-centric -application. It will be capable of accessing camera output, processing it and displaying the -result. - -#. Open Eclipse IDE, create a new clean workspace, create a new Android project - :menuselection:`File --> New --> Android Project` - -#. Set name, target, package and ``minSDKVersion`` accordingly. The minimal SDK version for build - with OpenCV4Android SDK is 11. Minimal device API Level (for application manifest) is 8. - -#. Allow Eclipse to create default activity. Lets name the activity ``HelloOpenCvActivity``. - -#. Choose Blank Activity with full screen layout. Lets name the layout ``HelloOpenCvLayout``. - -#. Import OpenCV library project to your workspace. - -#. Reference OpenCV library within your project properties. - - .. image:: images/dev_OCV_reference.png - :alt: Reference OpenCV library. - :align: center - -#. Edit your layout file as xml file and pass the following layout there: - - .. code-block:: xml - :linenos: - - - - - - - -#. Add the following permissions to the :file:`AndroidManifest.xml` file: - - .. code-block:: xml - :linenos: - - - - - - - - - - -#. Set application theme in AndroidManifest.xml to hide title and system buttons. - - .. code-block:: xml - :linenos: - - - -#. Add OpenCV library initialization to your activity. Fix errors by adding requited imports. - - .. code-block:: java - :linenos: - - private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { - @Override - public void onManagerConnected(int status) { - switch (status) { - case LoaderCallbackInterface.SUCCESS: - { - Log.i(TAG, "OpenCV loaded successfully"); - mOpenCvCameraView.enableView(); - } break; - default: - { - super.onManagerConnected(status); - } break; - } - } - }; - - @Override - public void onResume() - { - super.onResume(); - OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_6, this, mLoaderCallback); - } - -#. Defines that your activity implements ``CvCameraViewListener2`` interface and fix activity related - errors by defining missed methods. For this activity define ``onCreate``, ``onDestroy`` and - ``onPause`` and implement them according code snippet bellow. Fix errors by adding requited - imports. - - .. code-block:: java - :linenos: - - private CameraBridgeViewBase mOpenCvCameraView; - - @Override - public void onCreate(Bundle savedInstanceState) { - Log.i(TAG, "called onCreate"); - super.onCreate(savedInstanceState); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - setContentView(R.layout.HelloOpenCvLayout); - mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.HelloOpenCvView); - mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE); - mOpenCvCameraView.setCvCameraViewListener(this); - } - - @Override - public void onPause() - { - super.onPause(); - if (mOpenCvCameraView != null) - mOpenCvCameraView.disableView(); - } - - public void onDestroy() { - super.onDestroy(); - if (mOpenCvCameraView != null) - mOpenCvCameraView.disableView(); - } - - public void onCameraViewStarted(int width, int height) { - } - - public void onCameraViewStopped() { - } - - public Mat onCameraFrame(CvCameraViewFrame inputFrame) { - return inputFrame.rgba(); - } - -#. Run your application on device or emulator. - -Lets discuss some most important steps. Every Android application with UI must implement Activity -and View. By the first steps we create blank activity and default view layout. The simplest -OpenCV-centric application must implement OpenCV initialization, create its own view to show -preview from camera and implements ``CvCameraViewListener2`` interface to get frames from camera and -process it. - -First of all we create our application view using xml layout. Our layout consists of the only -one full screen component of class ``org.opencv.android.JavaCameraView``. This class is -implemented inside OpenCV library. It is inherited from ``CameraBridgeViewBase``, that extends -``SurfaceView`` and uses standard Android camera API. Alternatively you can use -``org.opencv.android.NativeCameraView`` class, that implements the same interface, but uses -``VideoCapture`` class as camera access back-end. ``opencv:show_fps="true"`` and -``opencv:camera_id="any"`` options enable FPS message and allow to use any camera on device. -Application tries to use back camera first. - -After creating layout we need to implement ``Activity`` class. OpenCV initialization process has -been already discussed above. In this sample we use asynchronous initialization. Implementation of -``CvCameraViewListener`` interface allows you to add processing steps after frame grabbing from -camera and before its rendering on screen. The most important function is ``onCameraFrame``. It is -callback function and it is called on retrieving frame from camera. The callback input is object -of ``CvCameraViewFrame`` class that represents frame from camera. - -.. note:: - Do not save or use ``CvCameraViewFrame`` object out of ``onCameraFrame`` callback. This object - does not have its own state and its behavior out of callback is unpredictable! - -It has ``rgba()`` and ``gray()`` methods that allows to get frame as RGBA and one channel gray scale -``Mat`` respectively. It expects that ``onCameraFrame`` function returns RGBA frame that will be -drawn on the screen. diff --git a/doc/tutorials/introduction/clojure_dev_intro/clojure_dev_intro.rst b/doc/tutorials/introduction/clojure_dev_intro/clojure_dev_intro.rst deleted file mode 100644 index 0ad47863eb..0000000000 --- a/doc/tutorials/introduction/clojure_dev_intro/clojure_dev_intro.rst +++ /dev/null @@ -1,728 +0,0 @@ -.. _clojure_dev_intro: - -Introduction to OpenCV Development with Clojure -*********************************************** - -As of OpenCV 2.4.4, OpenCV supports desktop Java development using -nearly the same interface as for Android development. - -`Clojure `_ is a contemporary LISP dialect hosted -by the Java Virtual Machine and it offers a complete interoperability -with the underlying JVM. This means that we should even be able to use -the Clojure REPL (Read Eval Print Loop) as and interactive programmable -interface to the underlying OpenCV engine. - -What we'll do in this tutorial -============================== - -This tutorial will help you in setting up a basic Clojure environment -for interactively learning OpenCV within the fully programmable -CLojure REPL. - -Tutorial source code --------------------- - -You can find a runnable source code of the sample in the -:file:`samples/java/clojure/simple-sample` folder of the OpenCV -repository. After having installed OpenCV and Clojure as explained in -the tutorial, issue the following command to run the sample from the -command line. - -.. code:: bash - - cd path/to/samples/java/clojure/simple-sample - lein run - -Preamble -======== - -For detailed instruction on installing OpenCV with desktop Java support -refer to the `corresponding tutorial `_. - -If you are in hurry, here is a minimum quick start guide to install -OpenCV on Mac OS X: - - NOTE 1: I'm assuming you already installed - `xcode `_, - `jdk `_ - and `Cmake `_. - -.. code:: bash - - cd ~/ - mkdir opt - git clone https://github.com/Itseez/opencv.git - cd opencv - git checkout 2.4 - mkdir build - cd build - cmake -DBUILD_SHARED_LIBS=OFF .. - ... - ... - make -j8 - # optional - # make install - -Install Leiningen -================= - -Once you installed OpenCV with desktop java support the only other -requirement is to install -`Leiningeng `_ which allows -you to manage the entire life cycle of your CLJ projects. - -The available `installation guide `_ is very easy to be followed: - -1. `Download the script `_ -2. Place it on your ``$PATH`` (cf. ``~/bin`` is a good choice if it is - on your ``path``.) -3. Set the script to be executable. (i.e. ``chmod 755 ~/bin/lein``). - -If you work on Windows, follow `this instruction `_ - -You now have both the OpenCV library and a fully installed basic Clojure -environment. What is now needed is to configure the Clojure environment -to interact with the OpenCV library. - -Install the localrepo Leiningen plugin -======================================= - -The set of commands (tasks in Leiningen parlance) natively supported by -Leiningen can be very easily extended by various plugins. One of them is -the `lein-localrepo `_ -plugin which allows to install any jar lib as an artifact in the local -maven repository of your machine (typically in the ``~/.m2/repository`` -directory of your username). - -We're going to use this ``lein`` plugin to add to the local maven -repository the opencv components needed by Java and Clojure to use the -opencv lib. - -Generally speaking, if you want to use a plugin on project base only, it -can be added directly to a CLJ project created by ``lein``. - -Instead, when you want a plugin to be available to any CLJ project in -your username space, you can add it to the ``profiles.clj`` in the -``~/.lein/`` directory. - -The ``lein-localrepo`` plugin will be useful to me in other CLJ -projects where I need to call native libs wrapped by a Java interface. -So I decide to make it available to any CLJ project: - -.. code:: bash - - mkdir ~/.lein - -Create a file named ``profiles.clj`` in the ``~/.lein`` directory and -copy into it the following content: - -.. code:: clojure - - {:user {:plugins [[lein-localrepo "0.5.2"]]}} - -Here we're saying that the version release ``"0.5.2"`` of the -``lein-localrepo`` plugin will be available to the ``:user`` profile for -any CLJ project created by ``lein``. - -You do not need to do anything else to install the plugin because it -will be automatically downloaded from a remote repository the very first -time you issue any ``lein`` task. - -Install the java specific libs as local repository -================================================== - -If you followed the standard documentation for installing OpenCV on your -computer, you should find the following two libs under the directory -where you built OpenCV: - -- the ``build/bin/opencv-247.jar`` java lib -- the ``build/lib/libopencv_java247.dylib`` native lib (or ``.so`` in - you built OpenCV a GNU/Linux OS) - -They are the only opencv libs needed by the JVM to interact with OpenCV. - -Take apart the needed opencv libs ---------------------------------- - -Create a new directory to store in the above two libs. Start by copying -into it the ``opencv-247.jar`` lib. - -.. code:: bash - - cd ~/opt - mkdir clj-opencv - cd clj-opencv - cp ~/opt/opencv/build/bin/opencv-247.jar . - -First lib done. - -Now, to be able to add the ``libopencv_java247.dylib`` shared native lib -to the local maven repository, we first need to package it as a jar -file. - -The native lib has to be copied into a directories layout which mimics -the names of your operating system and architecture. I'm using a Mac OS -X with a X86 64 bit architecture. So my layout will be the following: - -.. code:: bash - - mkdir -p native/macosx/x86_64 - -Copy into the ``x86_64`` directory the ``libopencv_java247.dylib`` lib. - -.. code:: bash - - cp ~/opt/opencv/build/lib/libopencv_java247.dylib native/macosx/x86_64/ - -If you're running OpenCV from a different OS/Architecture pair, here -is a summary of the mapping you can choose from. - -.. code:: bash - - OS - - Mac OS X -> macosx - Windows -> windows - Linux -> linux - SunOS -> solaris - - Architectures - - amd64 -> x86_64 - x86_64 -> x86_64 - x86 -> x86 - i386 -> x86 - arm -> arm - sparc -> sparc - -Package the native lib as a jar -------------------------------- - -Next you need to package the native lib in a jar file by using the -``jar`` command to create a new jar file from a directory. - -.. code:: bash - - jar -cMf opencv-native-247.jar native - -Note that ehe ``M`` option instructs the ``jar`` command to not create -a MANIFEST file for the artifact. - -Your directories layout should look like the following: - -.. code:: bash - - tree - . - |__ native - |   |__ macosx - |   |__ x86_64 - |   |__ libopencv_java247.dylib - | - |__ opencv-247.jar - |__ opencv-native-247.jar - - 3 directories, 3 files - -Locally install the jars ------------------------- - -We are now ready to add the two jars as artifacts to the local maven -repository with the help of the ``lein-localrepo`` plugin. - -.. code:: bash - - lein localrepo install opencv-247.jar opencv/opencv 2.4.7 - -Here the ``localrepo install`` task creates the ``2.4.7.`` release of -the ``opencv/opencv`` maven artifact from the ``opencv-247.jar`` lib and -then installs it into the local maven repository. The ``opencv/opencv`` -artifact will then be available to any maven compliant project -(Leiningen is internally based on maven). - -Do the same thing with the native lib previously wrapped in a new jar -file. - -.. code:: bash - - lein localrepo install opencv-native-247.jar opencv/opencv-native 2.4.7 - -Note that the groupId, ``opencv``, of the two artifacts is the same. We -are now ready to create a new CLJ project to start interacting with -OpenCV. - -Create a project ----------------- - -Create a new CLJ project by using the ``lein new`` task from the -terminal. - -.. code:: bash - - # cd in the directory where you work with your development projects (e.g. ~/devel) - lein new simple-sample - Generating a project called simple-sample based on the 'default' template. - To see other templates (app, lein plugin, etc), try `lein help new`. - -The above task creates the following ``simple-sample`` directories -layout: - -.. code:: bash - - tree simple-sample/ - simple-sample/ - |__ LICENSE - |__ README.md - |__ doc - |   |__ intro.md - | - |__ project.clj - |__ resources - |__ src - |   |__ simple_sample - |   |__ core.clj - |__ test - |__ simple_sample - |__ core_test.clj - - 6 directories, 6 files - -We need to add the two ``opencv`` artifacts as dependencies of the newly -created project. Open the ``project.clj`` and modify its dependencies -section as follows: - -.. code:: bash - - (defproject simple-sample "0.1.0-SNAPSHOT" - :description "FIXME: write description" - :url "http://example.com/FIXME" - :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[org.clojure/clojure "1.5.1"] - [opencv/opencv "2.4.7"] ; added line - [opencv/opencv-native "2.4.7"]]) ;added line - - -Note that The Clojure Programming Language is a jar artifact too. This -is why Clojure is called an hosted language. - -To verify that everything went right issue the ``lein deps`` task. The -very first time you run a ``lein`` task it will take sometime to -download all the required dependencies before executing the task -itself. - -.. code:: bash - - cd simple-sample - lein deps - ... - -The ``deps`` task reads and merges from the ``project.clj`` and the -``~/.lein/profiles.clj`` files all the dependencies of the -``simple-sample`` project and verifies if they have already been -cached in the local maven repository. If the task returns without -messages about not being able to retrieve the two new artifacts your -installation is correct, otherwise go back and double check that you -did everything right. - -REPLing with OpenCV -------------------- - -Now ``cd`` in the ``simple-sample`` directory and issue the following -``lein`` task: - -.. code:: bash - - cd simple-sample - lein repl - ... - ... - nREPL server started on port 50907 on host 127.0.0.1 - REPL-y 0.3.0 - Clojure 1.5.1 - Docs: (doc function-name-here) - (find-doc "part-of-name-here") - Source: (source function-name-here) - Javadoc: (javadoc java-object-or-class-here) - Exit: Control+D or (exit) or (quit) - Results: Stored in vars *1, *2, *3, an exception in *e - - user=> - -You can immediately interact with the REPL by issuing any CLJ expression -to be evaluated. - -.. code:: clojure - - user=> (+ 41 1) - 42 - user=> (println "Hello, OpenCV!") - Hello, OpenCV! - nil - user=> (defn foo [] (str "bar")) - #'user/foo - user=> (foo) - "bar" - -When ran from the home directory of a lein based project, even if the -``lein repl`` task automatically loads all the project dependencies, you -still need to load the opencv native library to be able to interact with -the OpenCV. - -.. code:: clojure - - user=> (clojure.lang.RT/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME) - nil - -Then you can start interacting with OpenCV by just referencing the fully -qualified names of its classes. - - NOTE 2: `Here `_ you can find the - full OpenCV Java API. - -.. code:: clojure - - user=> (org.opencv.core.Point. 0 0) - # - -Here we created a two dimensions opencv ``Point`` instance. Even if all -the java packages included within the java interface to OpenCV are -immediately available from the CLJ REPL, it's very annoying to prefix -the ``Point.`` instance constructors with the fully qualified package -name. - -Fortunately CLJ offer a very easy way to overcome this annoyance by -directly importing the ``Point`` class. - -.. code:: clojure - - user=> (import 'org.opencv.core.Point) - org.opencv.core.Point - user=> (def p1 (Point. 0 0)) - #'user/p1 - user=> p1 - # - user=> (def p2 (Point. 100 100)) - #'user/p2 - -We can even inspect the class of an instance and verify if the value of -a symbol is an instance of a ``Point`` java class. - -.. code:: clojure - - user=> (class p1) - org.opencv.core.Point - user=> (instance? org.opencv.core.Point p1) - true - -If we now want to use the opencv ``Rect`` class to create a rectangle, -we again have to fully qualify its constructor even if it leaves in -the same ``org.opencv.core`` package of the ``Point`` class. - -.. code:: clojure - - user=> (org.opencv.core.Rect. p1 p2) - # - -Again, the CLJ importing facilities is very handy and let you to map -more symbols in one shot. - -.. code:: clojure - - user=> (import '[org.opencv.core Point Rect Size]) - org.opencv.core.Size - user=> (def r1 (Rect. p1 p2)) - #'user/r1 - user=> r1 - # - user=> (class r1) - org.opencv.core.Rect - user=> (instance? org.opencv.core.Rect r1) - true - user=> (Size. 100 100) - # - user=> (def sq-100 (Size. 100 100)) - #'user/sq-100 - user=> (class sq-100) - org.opencv.core.Size - user=> (instance? org.opencv.core.Size sq-100) - true - -Obviously you can call methods on instances as well. - -.. code:: clojure - - user=> (.area r1) - 10000.0 - user=> (.area sq-100) - 10000.0 - -Or modify the value of a member field. - -.. code:: clojure - - user=> (set! (.x p1) 10) - 10 - user=> p1 - # - user=> (set! (.width sq-100) 10) - 10 - user=> (set! (.height sq-100) 10) - 10 - user=> (.area sq-100) - 100.0 - -If you find yourself not remembering a OpenCV class behavior, the -REPL gives you the opportunity to easily search the corresponding -javadoc documention: - -.. code:: clojure - - user=> (javadoc Rect) - "http://www.google.com/search?btnI=I%27m%20Feeling%20Lucky&q=allinurl:org/opencv/core/Rect.html" - -Mimic the OpenCV Java Tutorial Sample in the REPL -------------------------------------------------- - -Let's now try to port to Clojure the `opencv java tutorial sample `_. -Instead of writing it in a source file we're going to evaluate it at the -REPL. - -Following is the original Java source code of the cited sample. - -.. code:: java - - import org.opencv.core.Mat; - import org.opencv.core.CvType; - import org.opencv.core.Scalar; - - class SimpleSample { - - static{ System.loadLibrary("opencv_java244"); } - - public static void main(String[] args) { - Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0)); - System.out.println("OpenCV Mat: " + m); - Mat mr1 = m.row(1); - mr1.setTo(new Scalar(1)); - Mat mc5 = m.col(5); - mc5.setTo(new Scalar(5)); - System.out.println("OpenCV Mat data:\n" + m.dump()); - } - - } - -Add injections to the project ------------------------------ - -Before start coding, we'd like to eliminate the boring need of -interactively loading the native opencv lib any time we start a new REPL -to interact with it. - -First, stop the REPL by evaluating the ``(exit)`` expression at the REPL -prompt. - -.. code:: clojure - - user=> (exit) - Bye for now! - -Then open your ``project.clj`` file and edit it as follows: - -.. code:: clojure - - (defproject simple-sample "0.1.0-SNAPSHOT" - ... - :injections [(clojure.lang.RT/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME)]) - -Here we're saying to load the opencv native lib anytime we run the REPL -in such a way that we have not anymore to remember to manually do it. - -Rerun the ``lein repl`` task - -.. code:: bash - - lein repl - nREPL server started on port 51645 on host 127.0.0.1 - REPL-y 0.3.0 - Clojure 1.5.1 - Docs: (doc function-name-here) - (find-doc "part-of-name-here") - Source: (source function-name-here) - Javadoc: (javadoc java-object-or-class-here) - Exit: Control+D or (exit) or (quit) - Results: Stored in vars *1, *2, *3, an exception in *e - - user=> - -Import the interested OpenCV java interfaces. - -.. code:: clojure - - user=> (import '[org.opencv.core Mat CvType Scalar]) - org.opencv.core.Scalar - -We're going to mimic almost verbatim the original OpenCV java tutorial -to: - -- create a 5x10 matrix with all its elements intialized to 0 -- change the value of every element of the second row to 1 -- change the value of every element of the 6th column to 5 -- print the content of the obtained matrix - -.. code:: clojure - - user=> (def m (Mat. 5 10 CvType/CV_8UC1 (Scalar. 0 0))) - #'user/m - user=> (def mr1 (.row m 1)) - #'user/mr1 - user=> (.setTo mr1 (Scalar. 1 0)) - # - user=> (def mc5 (.col m 5)) - #'user/mc5 - user=> (.setTo mc5 (Scalar. 5 0)) - # - user=> (println (.dump m)) - [0, 0, 0, 0, 0, 5, 0, 0, 0, 0; - 1, 1, 1, 1, 1, 5, 1, 1, 1, 1; - 0, 0, 0, 0, 0, 5, 0, 0, 0, 0; - 0, 0, 0, 0, 0, 5, 0, 0, 0, 0; - 0, 0, 0, 0, 0, 5, 0, 0, 0, 0] - nil - -If you are accustomed to a functional language all those abused and -mutating nouns are going to irritate your preference for verbs. Even -if the CLJ interop syntax is very handy and complete, there is still -an impedance mismatch between any OOP language and any FP language -(bein Scala a mixed paradigms programming language). - -To exit the REPL type ``(exit)``, ``ctr-D`` or ``(quit)`` at the REPL -prompt. - -.. code:: clojure - - user=> (exit) - Bye for now! - -Interactively load and blur an image ------------------------------------- - -In the next sample you will learn how to interactively load and blur and -image from the REPL by using the following OpenCV methods: - -- the ``imread`` static method from the ``Highgui`` class to read an - image from a file -- the ``imwrite`` static method from the ``Highgui`` class to write an - image to a file -- the ``GaussianBlur`` static method from the ``Imgproc`` class to - apply to blur the original image - -We're also going to use the ``Mat`` class which is returned from the -``imread`` method and accpeted as the main argument to both the -``GaussianBlur`` and the ``imwrite`` methods. - -Add an image to the project ---------------------------- - -First we want to add an image file to a newly create directory for -storing static resources of the project. - -.. image:: images/lena.png - :alt: Original Image - :align: center - -.. code:: bash - - mkdir -p resources/images - cp ~/opt/opencv/doc/tutorials/introduction/desktop_java/images/lena.png resource/images/ - -Read the image --------------- - -Now launch the REPL as usual and start by importing all the OpenCV -classes we're going to use: - -.. code:: clojure - - lein repl - nREPL server started on port 50624 on host 127.0.0.1 - REPL-y 0.3.0 - Clojure 1.5.1 - Docs: (doc function-name-here) - (find-doc "part-of-name-here") - Source: (source function-name-here) - Javadoc: (javadoc java-object-or-class-here) - Exit: Control+D or (exit) or (quit) - Results: Stored in vars *1, *2, *3, an exception in *e - - user=> (import '[org.opencv.core Mat Size CvType] - '[org.opencv.imgcodecs Imgcodecs] - '[org.opencv.imgproc Imgproc]) - org.opencv.imgproc.Imgproc - -Now read the image from the ``resources/images/lena.png`` file. - -.. code:: clojure - - user=> (def lena (Highgui/imread "resources/images/lena.png")) - #'user/lena - user=> lena - # - -As you see, by simply evaluating the ``lena`` symbol we know that -``lena.png`` is a ``512x512`` matrix of ``CV_8UC3`` elements type. Let's -create a new ``Mat`` instance of the same dimensions and elements type. - -.. code:: clojure - - user=> (def blurred (Mat. 512 512 CvType/CV_8UC3)) - #'user/blurred - user=> - -Now apply a ``GaussianBlur`` filter using ``lena`` as the source matrix -and ``blurred`` as the destination matrix. - -.. code:: clojure - - user=> (Imgproc/GaussianBlur lena blurred (Size. 5 5) 3 3) - nil - -As a last step just save the ``blurred`` matrix in a new image file. - -.. code:: clojure - - user=> (Highgui/imwrite "resources/images/blurred.png" blurred) - true - user=> (exit) - Bye for now! - -Following is the new blurred image of Lena. - -.. image:: images/blurred.png - :alt: Blurred Image - :align: center - -Next Steps -========== - -This tutorial only introduces the very basic environment set up to be -able to interact with OpenCV in a CLJ REPL. - -I recommend any Clojure newbie to read the `Clojure Java Interop chapter `_ to get all you need to know -to interoperate with any plain java lib that has not been wrapped in -Clojure to make it usable in a more idiomatic and functional way within -Clojure. - -The OpenCV Java API does not wrap the ``highgui`` module -functionalities depending on ``Qt`` (e.g. ``namedWindow`` and -``imshow``. If you want to create windows and show images into them -while interacting with OpenCV from the REPL, at the moment you're left -at your own. You could use Java Swing to fill the gap. - - -License -------- - -Copyright © 2013 Giacomo (Mimmo) Cosenza aka Magomimmo - -Distributed under the BSD 3-clause License, the same of OpenCV. diff --git a/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.rst b/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.rst deleted file mode 100644 index 87f6d9d4d6..0000000000 --- a/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.rst +++ /dev/null @@ -1,115 +0,0 @@ - -.. _ARM-Linux-cross-compile: - -Cross compilation for ARM based Linux systems -********************************************* - -This steps are tested on Ubuntu Linux 12.04, but should work for other Linux distributions. -I case of other distributions package names and names of cross compilation tools may differ. -There are several popular EABI versions that are used on ARM platform. This tutorial is -written for *gnueabi* and *gnueabihf*, but other variants should work with minimal changes. - - -Prerequisites -============= - - * Host computer with Linux; - * Git; - * CMake 2.6 or higher; - * Cross compilation tools for ARM: gcc, libstc++, etc. Depending on target platform you need - to choose *gnueabi* or *gnueabihf* tools. - Install command for *gnueabi*: - - .. code-block:: bash - - sudo apt-get install gcc-arm-linux-gnueabi - - Install command for *gnueabihf*: - - .. code-block:: bash - - sudo apt-get install gcc-arm-linux-gnueabihf - - * pkgconfig; - * Python 2.6 for host system; - * [optional] ffmpeg or libav development packages for armeabi(hf): libavcodec-dev, libavformat-dev, libswscale-dev; - * [optional] GTK+2.x or higher, including headers (libgtk2.0-dev) for armeabi(hf); - * [optional] libdc1394 2.x; - * [optional] libjpeg-dev, libpng-dev, libtiff-dev, libjasper-dev for armeabi(hf). - - -Getting OpenCV Source Code -========================== - -You can use the latest stable OpenCV version available in *sourceforge* or you can grab the latest -snapshot from our `Git repository `_. - - -Getting the Latest Stable OpenCV Version ----------------------------------------- - -* Go to our `page on Sourceforge `_; - -* Download the source tarball and unpack it. - - -Getting the Cutting-edge OpenCV from the Git Repository -------------------------------------------------------- - -Launch Git client and clone `OpenCV repository `_ - -In Linux it can be achieved with the following command in Terminal: - -.. code-block:: bash - - cd ~/ - git clone https://github.com/Itseez/opencv.git - - -Building OpenCV -=============== - -#. Create a build directory, make it current and run the following command: - - .. code-block:: bash - - cmake [] -DCMAKE_TOOLCHAIN_FILE=/platforms/linux/arm-gnueabi.toolchain.cmake - - Toolchain uses *gnueabihf* EABI convention by default. Add ``-DSOFTFP=ON`` cmake argument to switch on softfp compiler. - - .. code-block:: bash - - cmake [] -DSOFTFP=ON -DCMAKE_TOOLCHAIN_FILE=/platforms/linux/arm-gnueabi.toolchain.cmake - - For example: - - .. code-block:: bash - - cd ~/opencv/platforms/linux - mkdir -p build_hardfp - cd build_hardfp - - cmake -DCMAKE_TOOLCHAIN_FILE=../arm-gnueabi.toolchain.cmake ../../.. - -#. Run make in build () directory: - - .. code-block:: bash - - make - -.. note:: - - Optionally you can strip symbols info from the created library via install/strip make target. - This option produces smaller binary (~ twice smaller) but makes further debugging harder. - -Enable hardware optimizations ------------------------------ - -Depending on target platform architecture different instruction sets can be used. By default -compiler generates code for armv5l without VFPv3 and NEON extensions. Add ``-DENABLE_VFPV3=ON`` -to cmake command line to enable code generation for VFPv3 and ``-DENABLE_NEON=ON`` for using -NEON SIMD extensions. - -TBB is supported on multi core ARM SoCs also. -Add ``-DWITH_TBB=ON`` and ``-DBUILD_TBB=ON`` to enable it. Cmake scripts download TBB sources -from official project site ``_ and build it. diff --git a/doc/tutorials/introduction/desktop_java/java_dev_intro.rst b/doc/tutorials/introduction/desktop_java/java_dev_intro.rst deleted file mode 100644 index b67ea0313b..0000000000 --- a/doc/tutorials/introduction/desktop_java/java_dev_intro.rst +++ /dev/null @@ -1,446 +0,0 @@ - -.. _Java_Dev_Intro: - - -Introduction to Java Development -******************************** - -As of OpenCV 2.4.4, OpenCV supports desktop Java development using nearly the same interface as for -Android development. This guide will help you to create your first Java (or Scala) application using OpenCV. -We will use either `Apache Ant `_ or `Simple Build Tool (SBT) `_ to build the application. - -If you want to use Eclipse head to :ref:`Java_Eclipse`. For further reading after this guide, look at the :ref:`Android_Dev_Intro` tutorials. - -What we'll do in this guide -=========================== - -In this guide, we will: - -* Get OpenCV with desktop Java support - -* Create an ``Ant`` or ``SBT`` project - -* Write a simple OpenCV application in Java or Scala - -The same process was used to create the samples in the :file:`samples/java` folder of the OpenCV repository, -so consult those files if you get lost. - -Get proper OpenCV -================= - -Starting from version 2.4.4 OpenCV includes desktop Java bindings. - -Download --------- - -The most simple way to get it is downloading the appropriate package of **version 2.4.4 or higher** from the -`OpenCV SourceForge repository `_. - -.. note:: Windows users can find the prebuilt files needed for Java development in - the :file:`opencv/build/java/` folder inside the package. - For other OSes it's required to build OpenCV from sources. - -Another option to get OpenCV sources is to clone `OpenCV git repository -`_. -In order to build OpenCV with Java bindings you need :abbr:`JDK (Java Development Kit)` -(we recommend `Oracle/Sun JDK 6 or 7 `_), -`Apache Ant `_ and `Python` v2.6 or higher to be installed. - -Build ------ - -Let's build OpenCV: - -.. code-block:: bash - - git clone git://github.com/Itseez/opencv.git - cd opencv - git checkout 2.4 - mkdir build - cd build - -Generate a Makefile or a MS Visual Studio* solution, or whatever you use for -building executables in your system: - -.. code-block:: bash - - cmake -DBUILD_SHARED_LIBS=OFF .. - -or - -.. code-block:: bat - - cmake -DBUILD_SHARED_LIBS=OFF -G "Visual Studio 10" .. - -.. note:: When OpenCV is built as a set of **static** libraries (``-DBUILD_SHARED_LIBS=OFF`` option) - the Java bindings dynamic library is all-sufficient, - i.e. doesn't depend on other OpenCV libs, but includes all the OpenCV code inside. - -Examine the output of CMake and ensure ``java`` is one of the modules "To be built". -If not, it's likely you're missing a dependency. You should troubleshoot by looking -through the CMake output for any Java-related tools that aren't found and installing them. - -.. image:: images/cmake_output.png - :alt: CMake output - :align: center - -.. note:: If ``CMake`` can't find Java in your system set the ``JAVA_HOME`` - environment variable with the path to installed JDK - before running it. E.g.: - - .. code-block:: bash - - export JAVA_HOME=/usr/lib/jvm/java-6-oracle - cmake -DBUILD_SHARED_LIBS=OFF .. - - -Now start the build: - -.. code-block:: bash - - make -j8 - -or - -.. code-block:: bat - - msbuild /m OpenCV.sln /t:Build /p:Configuration=Release /v:m - -Besides all this will create a ``jar`` containing the Java interface (:file:`bin/opencv-244.jar`) -and a native dynamic library containing Java bindings and all the OpenCV stuff -(:file:`lib/libopencv_java244.so` or :file:`bin/Release/opencv_java244.dll` respectively). -We'll use these files later. - -Java sample with Ant -==================== - -.. note:: - The described sample is provided with OpenCV library in the :file:`opencv/samples/java/ant` folder. - -* Create a folder where you'll develop this sample application. - -* In this folder create the :file:`build.xml` file with the following content using any text editor: - - .. code-block:: xml - :linenos: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .. note:: - This XML file can be reused for building other Java applications. - It describes a common folder structure in the lines 3 - 12 and common targets - for compiling and running the application. - - When reusing this XML don't forget to modify the project name in the line 1, - that is also the name of the `main` class (line 14). - The paths to OpenCV `jar` and `jni lib` are expected as parameters - (``"${ocvJarDir}"`` in line 5 and ``"${ocvLibDir}"`` in line 37), but - you can hardcode these paths for your convenience. - See `Ant documentation `_ for detailed description - of its build file format. - -* Create an :file:`src` folder next to the :file:`build.xml` file and a :file:`SimpleSample.java` file in it. - -* Put the following Java code into the :file:`SimpleSample.java` file: - .. code-block:: java - - import org.opencv.core.Core; - import org.opencv.core.Mat; - import org.opencv.core.CvType; - import org.opencv.core.Scalar; - - class SimpleSample { - - static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } - - public static void main(String[] args) { - System.out.println("Welcome to OpenCV " + Core.VERSION); - Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0)); - System.out.println("OpenCV Mat: " + m); - Mat mr1 = m.row(1); - mr1.setTo(new Scalar(1)); - Mat mc5 = m.col(5); - mc5.setTo(new Scalar(5)); - System.out.println("OpenCV Mat data:\n" + m.dump()); - } - - } - -* Run the following command in console in the folder containing :file:`build.xml`: - .. code-block:: bash - - ant -DocvJarDir=path/to/dir/containing/opencv-244.jar -DocvLibDir=path/to/dir/containing/opencv_java244/native/library - - For example: - - .. code-block:: bat - - ant -DocvJarDir=X:\opencv-2.4.4\bin -DocvLibDir=X:\opencv-2.4.4\bin\Release - - The command should initiate [re]building and running the sample. - You should see on the screen something like this: - - .. image:: images/ant_output.png - :alt: run app with Ant - :align: center - - -SBT project for Java and Scala -============================== - -Now we'll create a simple Java application using SBT. This serves as a brief introduction to -those unfamiliar with this build tool. We're using SBT because it is particularly easy and powerful. - -First, download and install `SBT `_ using the instructions on its `web site `_. - -Next, navigate to a new directory where you'd like the application source to live (outside :file:`opencv` dir). -Let's call it "JavaSample" and create a directory for it: - -.. code-block:: bash - - cd - mkdir JavaSample - -Now we will create the necessary folders and an SBT project: - -.. code-block:: bash - - cd JavaSample - mkdir -p src/main/java # This is where SBT expects to find Java sources - mkdir project # This is where the build definitions live - -Now open :file:`project/build.scala` in your favorite editor and paste the following. -It defines your project: - -.. code-block:: scala - - import sbt._ - import Keys._ - - object JavaSampleBuild extends Build { - def scalaSettings = Seq( - scalaVersion := "2.10.0", - scalacOptions ++= Seq( - "-optimize", - "-unchecked", - "-deprecation" - ) - ) - - def buildSettings = - Project.defaultSettings ++ - scalaSettings - - lazy val root = { - val settings = buildSettings ++ Seq(name := "JavaSample") - Project(id = "JavaSample", base = file("."), settings = settings) - } - } - -Now edit :file:`project/plugins.sbt` and paste the following. -This will enable auto-generation of an Eclipse project: - -.. code-block:: scala - - addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.0") - -Now run ``sbt`` from the :file:`JavaSample` root and from within SBT run ``eclipse`` to generate an eclipse project: - -.. code-block:: bash - - sbt # Starts the sbt console - > eclipse # Running "eclipse" from within the sbt console - -You should see something like this: - -.. image:: images/sbt_eclipse.png - :alt: SBT output - :align: center - -You can now import the SBT project to Eclipse using :guilabel:`Import ... -> Existing projects into workspace`. -Whether you actually do this is optional for the guide; -we'll be using SBT to build the project, so if you choose to use Eclipse it will just serve as a text editor. - -To test that everything is working, create a simple "Hello OpenCV" application. -Do this by creating a file :file:`src/main/java/HelloOpenCV.java` with the following contents: - -.. code-block:: java - - public class HelloOpenCV { - public static void main(String[] args) { - System.out.println("Hello, OpenCV"); - } - } - -Now execute ``run`` from the sbt console, or more concisely, run ``sbt run`` from the command line: - -.. code-block:: bash - - sbt run - -You should see something like this: - -.. image:: images/sbt_run.png - :alt: SBT run - :align: center - -Running SBT samples -------------------- - -Now we'll create a simple face detection application using OpenCV. - -First, create a :file:`lib/` folder and copy the OpenCV jar into it. -By default, SBT adds jars in the lib folder to the Java library search path. -You can optionally rerun ``sbt eclipse`` to update your Eclipse project. - -.. code-block:: bash - - mkdir lib - cp /build/bin/opencv_.jar lib/ - sbt eclipse - -Next, create the directory :file:`src/main/resources` and download this Lena image into it: - -.. image:: images/lena.png - :alt: Lena - :align: center - -Make sure it's called :file:`"lena.png"`. -Items in the resources directory are available to the Java application at runtime. - -Next, copy :file:`lbpcascade_frontalface.xml` from :file:`opencv/data/lbpcascades/` into the :file:`resources` -directory: - -.. code-block:: bash - - cp /data/lbpcascades/lbpcascade_frontalface.xml src/main/resources/ - -Now modify src/main/java/HelloOpenCV.java so it contains the following Java code: - -.. code-block:: java - - import org.opencv.core.Core; - import org.opencv.core.Mat; - import org.opencv.core.MatOfRect; - import org.opencv.core.Point; - import org.opencv.core.Rect; - import org.opencv.core.Scalar; - import org.opencv.imgcodecs.Imgcodecs; - import org.opencv.objdetect.CascadeClassifier; - - // - // Detects faces in an image, draws boxes around them, and writes the results - // to "faceDetection.png". - // - class DetectFaceDemo { - public void run() { - System.out.println("\nRunning DetectFaceDemo"); - - // Create a face detector from the cascade file in the resources - // directory. - CascadeClassifier faceDetector = new CascadeClassifier(getClass().getResource("/lbpcascade_frontalface.xml").getPath()); - Mat image = Imgcodecs.imread(getClass().getResource("/lena.png").getPath()); - - // Detect faces in the image. - // MatOfRect is a special container class for Rect. - MatOfRect faceDetections = new MatOfRect(); - faceDetector.detectMultiScale(image, faceDetections); - - System.out.println(String.format("Detected %s faces", faceDetections.toArray().length)); - - // Draw a bounding box around each face. - for (Rect rect : faceDetections.toArray()) { - Imgproc.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0)); - } - - // Save the visualized detection. - String filename = "faceDetection.png"; - System.out.println(String.format("Writing %s", filename)); - Imgcodecs.imwrite(filename, image); - } - } - - public class HelloOpenCV { - public static void main(String[] args) { - System.out.println("Hello, OpenCV"); - - // Load the native library. - System.loadLibrary(Core.NATIVE_LIBRARY_NAME); - new DetectFaceDemo().run(); - } - } - -Note the call to ``System.loadLibrary(Core.NATIVE_LIBRARY_NAME)``. -This command must be executed exactly once per Java process prior to using any native OpenCV methods. -If you don't call it, you will get ``UnsatisfiedLink errors``. -You will also get errors if you try to load OpenCV when it has already been loaded. - -Now run the face detection app using ``sbt run``: - -.. code-block:: bash - - sbt run - -You should see something like this: - -.. image:: images/sbt_run_face.png - :alt: SBT run - :align: center - -It should also write the following image to :file:`faceDetection.png`: - -.. image:: images/faceDetection.png - :alt: Detected face - :align: center - -You're done! -Now you have a sample Java application working with OpenCV, so you can start the work on your own. -We wish you good luck and many years of joyful life! diff --git a/doc/tutorials/introduction/display_image/display_image.markdown b/doc/tutorials/introduction/display_image/display_image.markdown index 680b61d84a..fe90dfb839 100644 --- a/doc/tutorials/introduction/display_image/display_image.markdown +++ b/doc/tutorials/introduction/display_image/display_image.markdown @@ -21,8 +21,6 @@ Download the source code from Explanation ----------- -@dontinclude cpp/tutorial_code/introduction/display_image/display_image.cpp - In OpenCV 2 we have multiple modules. Each one takes care of a different area or approach towards image processing. You could already observe this in the structure of the user guide of these tutorials itself. Before you use any of them you first need to include the header files where the @@ -33,25 +31,24 @@ You'll almost always end up using the: - *core* section, as here are defined the basic building blocks of the library - *highgui* module, as this contains the functions for input and output operations -@until +@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp includes We also include the *iostream* to facilitate console line output and input. To avoid data structure and function name conflicts with other libraries, OpenCV has its own namespace: *cv*. To avoid the need appending prior each of these the *cv::* keyword you can import the namespace in the whole file by using the lines: -@line using namespace cv +@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp namespace This is true for the STL library too (used for console I/O). Now, let's analyze the *main* function. We start up assuring that we acquire a valid image name argument from the command line. Otherwise take a picture by default: "HappyFish.jpg". -@skip string -@until } +@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp load Then create a *Mat* object that will store the data of the loaded image. -@skipline Mat +@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp mat Now we call the @ref cv::imread function which loads the image name specified by the first argument (*argv[1]*). The second argument specifies the format in what we want the image. This may be: @@ -60,7 +57,7 @@ Now we call the @ref cv::imread function which loads the image name specified by - IMREAD_GRAYSCALE ( 0) loads the image as an intensity one - IMREAD_COLOR (\>0) loads the image in the RGB format -@skipline image = imread +@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp imread @note OpenCV offers support for the image formats Windows bitmap (bmp), portable image formats (pbm, @@ -82,18 +79,18 @@ the image it contains from a size point of view. It may be: would like the image to keep its aspect ratio (*WINDOW_KEEPRATIO*) or not (*WINDOW_FREERATIO*). -@skipline namedWindow +@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp window Finally, to update the content of the OpenCV window with a new image use the @ref cv::imshow function. Specify the OpenCV window name to update and the image to use during this operation: -@skipline imshow +@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp imshow Because we want our window to be displayed until the user presses a key (otherwise the program would end far too quickly), we use the @ref cv::waitKey function whose only parameter is just how long should it wait for a user input (measured in milliseconds). Zero means to wait forever. -@skipline waitKey +@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp wait Result ------ @@ -101,7 +98,7 @@ Result - Compile your code and then run the executable giving an image path as argument. If you're on Windows the executable will of course contain an *exe* extension too. Of course assure the image file is near your program file. - @code{.bash} + @code{.sh} ./DisplayImage HappyFish.jpg @endcode - You should get a nice window as the one shown below: diff --git a/doc/tutorials/introduction/display_image/display_image.rst b/doc/tutorials/introduction/display_image/display_image.rst deleted file mode 100644 index d4617cc126..0000000000 --- a/doc/tutorials/introduction/display_image/display_image.rst +++ /dev/null @@ -1,129 +0,0 @@ -.. _Display_Image: - -Load and Display an Image -************************* - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Load an image (using :imread:`imread <>`) - * Create a named OpenCV window (using :named_window:`namedWindow <>`) - * Display an image in an OpenCV window (using :imshow:`imshow <>`) - -Source Code -=========== - -Download the source code from `here `_. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp - :language: cpp - :tab-width: 4 - :linenos: - -Explanation -============ - -In OpenCV 2 we have multiple modules. Each one takes care of a different area or approach towards image processing. You could already observe this in the structure of the user guide of these tutorials itself. Before you use any of them you first need to include the header files where the content of each individual module is declared. - -You'll almost always end up using the: - -.. container:: enumeratevisibleitemswithsquare - - + *core* section, as here are defined the basic building blocks of the library - + *highgui* module, as this contains the functions for input and output operations - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp - :language: cpp - :tab-width: 4 - :lines: 1-6 - -We also include the *iostream* to facilitate console line output and input. To avoid data structure and function name conflicts with other libraries, OpenCV has its own namespace: *cv*. To avoid the need appending prior each of these the *cv::* keyword you can import the namespace in the whole file by using the lines: - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp - :language: cpp - :tab-width: 4 - :lines: 8-9 - -This is true for the STL library too (used for console I/O). Now, let's analyze the *main* function. We start up assuring that we acquire a valid image name argument from the command line. Otherwise take a picture by default: "HappyFish.jpg". - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp - :language: cpp - :tab-width: 4 - :lines: 13-17 - -Then create a *Mat* object that will store the data of the loaded image. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp - :language: cpp - :tab-width: 4 - :lines: 19 - -Now we call the :imread:`imread <>` function which loads the image name specified by the first argument (*argv[1]*). The second argument specifies the format in what we want the image. This may be: - -.. container:: enumeratevisibleitemswithsquare - - + IMREAD_UNCHANGED (<0) loads the image as is (including the alpha channel if present) - + IMREAD_GRAYSCALE ( 0) loads the image as an intensity one - + IMREAD_COLOR (>0) loads the image in the RGB format - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp - :language: cpp - :tab-width: 4 - :lines: 20 - -.. note:: - - OpenCV offers support for the image formats Windows bitmap (bmp), portable image formats (pbm, pgm, ppm) and Sun raster (sr, ras). With help of plugins (you need to specify to use them if you build yourself the library, nevertheless in the packages we ship present by default) you may also load image formats like JPEG (jpeg, jpg, jpe), JPEG 2000 (jp2 - codenamed in the CMake as Jasper), TIFF files (tiff, tif) and portable network graphics (png). Furthermore, OpenEXR is also a possibility. - -After checking that the image data was loaded correctly, we want to display our image, so we create an OpenCV window using the :named_window:`namedWindow <>` function. These are automatically managed by OpenCV once you create them. For this you need to specify its name and how it should handle the change of the image it contains from a size point of view. It may be: - -.. container:: enumeratevisibleitemswithsquare - - + *WINDOW_AUTOSIZE* is the only supported one if you do not use the Qt backend. In this case the window size will take up the size of the image it shows. No resize permitted! - + *WINDOW_NORMAL* on Qt you may use this to allow window resize. The image will resize itself according to the current window size. By using the | operator you also need to specify if you would like the image to keep its aspect ratio (*WINDOW_KEEPRATIO*) or not (*WINDOW_FREERATIO*). - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp - :language: cpp - :lines: 28 - :tab-width: 4 - -Finally, to update the content of the OpenCV window with a new image use the :imshow:`imshow <>` function. Specify the OpenCV window name to update and the image to use during this operation: - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp - :language: cpp - :lines: 29 - :tab-width: 4 - -Because we want our window to be displayed until the user presses a key (otherwise the program would end far too quickly), we use the :wait_key:`waitKey <>` function whose only parameter is just how long should it wait for a user input (measured in milliseconds). Zero means to wait forever. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp - :language: cpp - :lines: 31 - :tab-width: 4 - -Result -======= - -.. container:: enumeratevisibleitemswithsquare - - * Compile your code and then run the executable giving an image path as argument. If you're on Windows the executable will of course contain an *exe* extension too. Of course assure the image file is near your program file. - - .. code-block:: bash - - ./DisplayImage HappyFish.jpg - - * You should get a nice window as the one shown below: - - .. image:: images/Display_Image_Tutorial_Result.jpg - :alt: Display Image Tutorial - Final Result - :align: center - - .. raw:: html - -
- -
diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.jpg b/doc/tutorials/introduction/images/Display_Image_Tutorial_Result.jpg similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/Display_Image_Tutorial_Result.jpg rename to doc/tutorials/introduction/images/Display_Image_Tutorial_Result.jpg diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/Java_logo.png b/doc/tutorials/introduction/images/Java_logo.png similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/Java_logo.png rename to doc/tutorials/introduction/images/Java_logo.png diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.jpg b/doc/tutorials/introduction/images/Load_Save_Image_Result_1.jpg similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/Load_Save_Image_Result_1.jpg rename to doc/tutorials/introduction/images/Load_Save_Image_Result_1.jpg diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/android_logo.png b/doc/tutorials/introduction/images/android_logo.png similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/android_logo.png rename to doc/tutorials/introduction/images/android_logo.png diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/clojure-logo.png b/doc/tutorials/introduction/images/clojure-logo.png similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/clojure-logo.png rename to doc/tutorials/introduction/images/clojure-logo.png diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/eclipse-logo.png b/doc/tutorials/introduction/images/eclipse-logo.png similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/eclipse-logo.png rename to doc/tutorials/introduction/images/eclipse-logo.png diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/eclipse_cpp_logo.jpeg b/doc/tutorials/introduction/images/eclipse_cpp_logo.jpeg similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/eclipse_cpp_logo.jpeg rename to doc/tutorials/introduction/images/eclipse_cpp_logo.jpeg diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.jpg b/doc/tutorials/introduction/images/gccegg-65.jpg similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/gccegg-65.jpg rename to doc/tutorials/introduction/images/gccegg-65.jpg diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/how_to_write_a_tutorial.png b/doc/tutorials/introduction/images/how_to_write_a_tutorial.png similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/how_to_write_a_tutorial.png rename to doc/tutorials/introduction/images/how_to_write_a_tutorial.png diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/opencv_ios.png b/doc/tutorials/introduction/images/opencv_ios.png similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/opencv_ios.png rename to doc/tutorials/introduction/images/opencv_ios.png diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/ubuntu-logo.jpg b/doc/tutorials/introduction/images/ubuntu-logo.jpg similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/ubuntu-logo.jpg rename to doc/tutorials/introduction/images/ubuntu-logo.jpg diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/visual-studio-2010-logo.jpg b/doc/tutorials/introduction/images/visual-studio-2010-logo.jpg similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/visual-studio-2010-logo.jpg rename to doc/tutorials/introduction/images/visual-studio-2010-logo.jpg diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/visual_studio_image_watch.png b/doc/tutorials/introduction/images/visual_studio_image_watch.png similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/visual_studio_image_watch.png rename to doc/tutorials/introduction/images/visual_studio_image_watch.png diff --git a/doc/tutorials/introduction/table_of_content_introduction/images/windows_logo.jpg b/doc/tutorials/introduction/images/windows_logo.jpg similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/images/windows_logo.jpg rename to doc/tutorials/introduction/images/windows_logo.jpg diff --git a/doc/tutorials/introduction/ios_install/ios_install.rst b/doc/tutorials/introduction/ios_install/ios_install.rst deleted file mode 100644 index 2973b7ec2b..0000000000 --- a/doc/tutorials/introduction/ios_install/ios_install.rst +++ /dev/null @@ -1,46 +0,0 @@ -.. _iOS-Installation: - -Installation in iOS -******************* - -Required Packages -================= - - * CMake 2.8.8 or higher - * Xcode 4.2 or higher - -Getting the Cutting-edge OpenCV from Git Repository ---------------------------------------------------- - -Launch GIT client and clone OpenCV repository from `here `_ - -In MacOS it can be done using the following command in Terminal: - -.. code-block:: bash - - cd ~/ - git clone https://github.com/Itseez/opencv.git - - -Building OpenCV from Source, using CMake and Command Line -========================================================= - -#. Make symbolic link for Xcode to let OpenCV build scripts find the compiler, header files etc. - - .. code-block:: bash - - cd / - sudo ln -s /Applications/Xcode.app/Contents/Developer Developer - -#. Build OpenCV framework: - - .. code-block:: bash - - cd ~/ - python opencv/platforms/ios/build_framework.py ios - -If everything's fine, a few minutes later you will get ~//ios/opencv2.framework. You can add this framework to your Xcode projects. - -Further Reading -=============== -You can find several OpenCV+iOS tutorials here :ref:`Table-Of-Content-iOS`. diff --git a/doc/tutorials/introduction/java_eclipse/java_eclipse.rst b/doc/tutorials/introduction/java_eclipse/java_eclipse.rst deleted file mode 100644 index bc2247da9d..0000000000 --- a/doc/tutorials/introduction/java_eclipse/java_eclipse.rst +++ /dev/null @@ -1,110 +0,0 @@ - -.. _Java_Eclipse: - - -Using OpenCV Java with Eclipse -********************************************* - -Since version 2.4.4 `OpenCV supports Java `_. In this tutorial I will explain how to setup development environment for using OpenCV Java with Eclipse in **Windows**, so you can enjoy the benefits of garbage collected, very refactorable (rename variable, extract method and whatnot) modern language that enables you to write code with less effort and make less mistakes. Here we go. - - -Configuring Eclipse -=================== - -First, obtain a fresh release of OpenCV `from download page `_ and extract it under a simple location like ``C:\OpenCV-2.4.6\``. I am using version 2.4.6, but the steps are more or less the same for other versions. - -Now, we will define OpenCV as a user library in Eclipse, so we can reuse the configuration for any project. Launch Eclipse and select :guilabel:`Window --> Preferences` from the menu. - -.. image:: images/1-window-preferences.png - :alt: Eclipse preferences - :align: center - -Navigate under :guilabel:`Java --> Build Path --> User Libraries` and click :guilabel:`New...`. - -.. image:: images/2-user-library-new.png - :alt: Creating a new library - :align: center - -Enter a name, e.g. ``OpenCV-2.4.6``, for your new library. - -.. image:: images/3-library-name.png - :alt: Naming the new library - :align: center - -Now select your new user library and click :guilabel:`Add External JARs...`. - -.. image:: images/4-add-external-jars.png - :alt: Adding external jar - :align: center - -Browse through ``C:\OpenCV-2.4.6\build\java\`` and select ``opencv-246.jar``. After adding the jar, extend the :guilabel:`opencv-246.jar` and select :guilabel:`Native library location` and press :guilabel:`Edit...`. - -.. image:: images/5-native-library.png - :alt: Selecting native library location 1 - :align: center - -Select :guilabel:`External Folder...` and browse to select the folder ``C:\OpenCV-2.4.6\build\java\x64``. If you have a 32-bit system you need to select the ``x86`` folder instead of ``x64``. - -.. image:: images/6-external-folder.png - :alt: Selecting native library location 2 - :align: center - -Your user library configuration should look like this: - -.. image:: images/7-user-library-final.png - :alt: Selecting native library location 2 - :align: center - - -Testing the configuration on a new Java project -===================================================== - -Now start creating a new Java project. - -.. image:: images/7_5-new-java-project.png - :alt: Creating new Java project - :align: center - -On the :guilabel:`Java Settings` step, under :guilabel:`Libraries` tab, select :guilabel:`Add Library...` and select :guilabel:`OpenCV-2.4.6`, then click :guilabel:`Finish`. - -.. image:: images/8-add-library.png - :alt: Adding user defined library 1 - :align: center - -.. image:: images/9-select-user-lib.png - :alt: Adding user defined library 2 - :align: center - - -Libraries should look like this: - -.. image:: images/10-new-project-created.png - :alt: Adding user defined library - :align: center - - -Now you have created and configured a new Java project it is time to test it. Create a new java file. Here is a starter code for your convenience: - -.. code-block:: java - - import org.opencv.core.Core; - import org.opencv.core.CvType; - import org.opencv.core.Mat; - - public class Hello - { - public static void main( String[] args ) - { - System.loadLibrary( Core.NATIVE_LIBRARY_NAME ); - Mat mat = Mat.eye( 3, 3, CvType.CV_8UC1 ); - System.out.println( "mat = " + mat.dump() ); - } - } - -When you run the code you should see 3x3 identity matrix as output. - -.. image:: images/11-the-code.png - :alt: Adding user defined library - :align: center - -That is it, whenever you start a new project just add the OpenCV user library that you have defined to your project and you are good to go. Enjoy your powerful, less painful development environment :) \ No newline at end of file diff --git a/doc/tutorials/introduction/linux_eclipse/linux_eclipse.rst b/doc/tutorials/introduction/linux_eclipse/linux_eclipse.rst deleted file mode 100644 index 74e0ff9e09..0000000000 --- a/doc/tutorials/introduction/linux_eclipse/linux_eclipse.rst +++ /dev/null @@ -1,247 +0,0 @@ -.. _Linux_Eclipse_Usage: - -Using OpenCV with Eclipse (plugin CDT) -**************************************** - -.. note:: - Two ways, one by forming a project directly, and another by CMake - -Prerequisites -=============== - -1. Having installed `Eclipse `_ in your workstation (only the CDT plugin for C/C++ is needed). You can follow the following steps: - - * Go to the Eclipse site - - * Download `Eclipse IDE for C/C++ Developers `_ . Choose the link according to your workstation. - -#. Having installed OpenCV. If not yet, go :ref:`here `. - -Making a project -================= - -1. Start Eclipse. Just run the executable that comes in the folder. - -#. Go to **File -> New -> C/C++ Project** - - .. image:: images/a0.png - :alt: Eclipse Tutorial Screenshot 0 - :align: center - -#. Choose a name for your project (i.e. DisplayImage). An **Empty Project** should be okay for this example. - - .. image:: images/a1.png - :alt: Eclipse Tutorial Screenshot 1 - :align: center - -#. Leave everything else by default. Press **Finish**. - -#. Your project (in this case DisplayImage) should appear in the **Project Navigator** (usually at the left side of your window). - - .. image:: images/a3.png - :alt: Eclipse Tutorial Screenshot 3 - :align: center - - -#. Now, let's add a source file using OpenCV: - - * Right click on **DisplayImage** (in the Navigator). **New -> Folder** . - - .. image:: images/a4.png - :alt: Eclipse Tutorial Screenshot 4 - :align: center - - * Name your folder **src** and then hit **Finish** - - * Right click on your newly created **src** folder. Choose **New source file**: - - * Call it **DisplayImage.cpp**. Hit **Finish** - - .. image:: images/a7.png - :alt: Eclipse Tutorial Screenshot 7 - :align: center - -#. So, now you have a project with a empty .cpp file. Let's fill it with some sample code (in other words, copy and paste the snippet below): - - .. code-block:: cpp - - #include - - using namespace cv; - - int main( int argc, char** argv ) - { - Mat image; - image = imread( argv[1], 1 ); - - if( argc != 2 || !image.data ) - { - printf( "No image data \n" ); - return -1; - } - - namedWindow( "Display Image", WINDOW_AUTOSIZE ); - imshow( "Display Image", image ); - - waitKey(0); - - return 0; - } - -#. We are only missing one final step: To tell OpenCV where the OpenCV headers and libraries are. For this, do the following: - - * Go to **Project-->Properties** - - * In **C/C++ Build**, click on **Settings**. At the right, choose the **Tool Settings** Tab. Here we will enter the headers and libraries info: - - a. In **GCC C++ Compiler**, go to **Includes**. In **Include paths(-l)** you should include the path of the folder where opencv was installed. In our example, this is ``/usr/local/include/opencv``. - - .. image:: images/a9.png - :alt: Eclipse Tutorial Screenshot 9 - :align: center - - .. note:: - If you do not know where your opencv files are, open the **Terminal** and type: - - .. code-block:: bash - - pkg-config --cflags opencv - - For instance, that command gave me this output: - - .. code-block:: bash - - -I/usr/local/include/opencv -I/usr/local/include - - - b. Now go to **GCC C++ Linker**,there you have to fill two spaces: - - First in **Library search path (-L)** you have to write the path to where the opencv libraries reside, in my case the path is: - :: - - /usr/local/lib - - Then in **Libraries(-l)** add the OpenCV libraries that you may need. Usually just the 3 first on the list below are enough (for simple applications) . In my case, I am putting all of them since I plan to use the whole bunch: - - - opencv_core - opencv_imgproc - opencv_highgui - opencv_ml - opencv_video - opencv_features2d - opencv_calib3d - opencv_objdetect - opencv_contrib - opencv_legacy - opencv_flann - - .. image:: images/a10.png - :alt: Eclipse Tutorial Screenshot 10 - :align: center - - If you don't know where your libraries are (or you are just psychotic and want to make sure the path is fine), type in **Terminal**: - - .. code-block:: bash - - pkg-config --libs opencv - - - My output (in case you want to check) was: - .. code-block:: bash - - -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -lopencv_flann - - Now you are done. Click **OK** - - * Your project should be ready to be built. For this, go to **Project->Build all** - - In the Console you should get something like - - .. image:: images/a12.png - :alt: Eclipse Tutorial Screenshot 12 - :align: center - - If you check in your folder, there should be an executable there. - -Running the executable -======================== - -So, now we have an executable ready to run. If we were to use the Terminal, we would probably do something like: - -.. code-block:: bash - - cd - cd src - ./DisplayImage ../images/HappyLittleFish.png - -Assuming that the image to use as the argument would be located in /images/HappyLittleFish.png. We can still do this, but let's do it from Eclipse: - - -#. Go to **Run->Run Configurations** - -#. Under C/C++ Application you will see the name of your executable + Debug (if not, click over C/C++ Application a couple of times). Select the name (in this case **DisplayImage Debug**). - -#. Now, in the right side of the window, choose the **Arguments** Tab. Write the path of the image file we want to open (path relative to the workspace/DisplayImage folder). Let's use **HappyLittleFish.png**: - - .. image:: images/a14.png - :alt: Eclipse Tutorial Screenshot 14 - :align: center - -#. Click on the **Apply** button and then in Run. An OpenCV window should pop up with the fish image (or whatever you used). - - .. image:: images/a15.jpg - :alt: Eclipse Tutorial Screenshot 15 - :align: center - -#. Congratulations! You are ready to have fun with OpenCV using Eclipse. - -================================================== -V2: Using CMake+OpenCV with Eclipse (plugin CDT) -================================================== - -Say you have or create a new file, *helloworld.cpp* in a directory called *foo*: - -.. code-block:: cpp - - - #include - using namespace cv; - - int main ( int argc, char **argv ) - { - Mat img(480, 640, CV_8U); - putText(img, "Hello World!", Point( 200, 400 ), FONT_HERSHEY_SIMPLEX | FONT_ITALIC, 1.0, Scalar( 255, 255, 0 )); - imshow("My Window", img); - waitKey(); - return 0; - } - -1. Create a build directory, say, under *foo*: ``mkdir /build``. Then ``cd build``. - -#. Put a *CmakeLists.txt* file in build: - -.. code-block:: bash - - PROJECT( helloworld_proj ) - FIND_PACKAGE( OpenCV REQUIRED ) - ADD_EXECUTABLE( helloworld helloworld.cxx ) - TARGET_LINK_LIBRARIES( helloworld ${OpenCV_LIBS} ) - -#. Run: ``cmake-gui ..`` and make sure you fill in where opencv was built. - -#. Then click ``configure`` and then ``generate``. If it's OK, **quit cmake-gui** - -#. Run ``make -j4`` *(the ``-j4`` is optional, it just tells the compiler to build in 4 threads)*. Make sure it builds. - -#. Start ``eclipse`` . Put the workspace in some directory but **not** in ``foo`` or ``foo\\build`` - -#. Right click in the ``Project Explorer`` section. Select ``Import`` And then open the ``C/C++`` filter. Choose *Existing Code* as a Makefile Project`` - -#. Name your project, say *helloworld*. Browse to the Existing Code location ``foo\\build`` (where you ran your cmake-gui from). Select *Linux GCC* in the *"Toolchain for Indexer Settings"* and press *Finish*. - -#. Right click in the ``Project Explorer`` section. Select ``Properties``. Under ``C/C++ Build``, set the *build directory:* from something like ``${workspace_loc:/helloworld}`` to ``${workspace_loc:/helloworld}/build`` since that's where you are building to. - - a. You can also optionally modify the ``Build command:`` from ``make`` to something like ``make VERBOSE=1 -j4`` which tells the compiler to produce detailed symbol files for debugging and also to compile in 4 parallel threads. - -#. Done! diff --git a/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst b/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst deleted file mode 100644 index f1f8205577..0000000000 --- a/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.rst +++ /dev/null @@ -1,92 +0,0 @@ -.. _Linux_GCC_Usage: - -Using OpenCV with gcc and CMake -********************************* - -.. note:: - We assume that you have successfully installed OpenCV in your workstation. - -.. container:: enumeratevisibleitemswithsquare - - * The easiest way of using OpenCV in your code is to use `CMake `_. A few advantages (taken from the Wiki): - - #. No need to change anything when porting between Linux and Windows - #. Can easily be combined with other tools by CMake( i.e. Qt, ITK and VTK ) - - * If you are not familiar with CMake, checkout the `tutorial `_ on its website. - -Steps -====== - -Create a program using OpenCV -------------------------------- - -Let's use a simple program such as DisplayImage.cpp shown below. - -.. code-block:: cpp - - #include - #include - - using namespace cv; - - int main(int argc, char** argv ) - { - if ( argc != 2 ) - { - printf("usage: DisplayImage.out \n"); - return -1; - } - - Mat image; - image = imread( argv[1], 1 ); - - if ( !image.data ) - { - printf("No image data \n"); - return -1; - } - namedWindow("Display Image", WINDOW_AUTOSIZE ); - imshow("Display Image", image); - - waitKey(0); - - return 0; - } - -Create a CMake file ---------------------- -Now you have to create your CMakeLists.txt file. It should look like this: - -.. code-block:: cmake - - cmake_minimum_required(VERSION 2.8) - project( DisplayImage ) - find_package( OpenCV REQUIRED ) - include_directories( ${OpenCV_INCLUDE_DIRS} ) - add_executable( DisplayImage DisplayImage.cpp ) - target_link_libraries( DisplayImage ${OpenCV_LIBS} ) - -Generate the executable -------------------------- -This part is easy, just proceed as with any other project using CMake: - -.. code-block:: bash - - cd - cmake . - make - -Result --------- -By now you should have an executable (called DisplayImage in this case). You just have to run it giving an image location as an argument, i.e.: - -.. code-block:: bash - - ./DisplayImage lena.jpg - -You should get a nice window as the one shown below: - -.. image:: images/GCC_CMake_Example_Tutorial.jpg - :alt: Display Image - Lena - :align: center diff --git a/doc/tutorials/introduction/linux_install/linux_install.rst b/doc/tutorials/introduction/linux_install/linux_install.rst deleted file mode 100644 index 5d1504f48f..0000000000 --- a/doc/tutorials/introduction/linux_install/linux_install.rst +++ /dev/null @@ -1,150 +0,0 @@ -.. _Linux-Installation: - -Installation in Linux -********************* -These steps have been tested for Ubuntu 10.04 but should work with other distros as well. - -Required Packages -================= - -* GCC 4.4.x or later -* CMake 2.8.7 or higher -* Git -* GTK+2.x or higher, including headers (libgtk2.0-dev) -* pkg-config -* Python 2.6 or later and Numpy 1.5 or later with developer packages (python-dev, python-numpy) -* ffmpeg or libav development packages: libavcodec-dev, libavformat-dev, libswscale-dev -* [optional] libtbb2 libtbb-dev -* [optional] libdc1394 2.x -* [optional] libjpeg-dev, libpng-dev, libtiff-dev, libjasper-dev, libdc1394-22-dev - -The packages can be installed using a terminal and the following commands or by using Synaptic Manager: - - .. code-block:: bash - - [compiler] sudo apt-get install build-essential - [required] sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev - [optional] sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev - -Getting OpenCV Source Code -========================== - -You can use the latest stable OpenCV version or you can grab the latest snapshot from our `Git repository `_. - -Getting the Latest Stable OpenCV Version ----------------------------------------- - -* Go to our `downloads page `_. - -* Download the source archive and unpack it. - -Getting the Cutting-edge OpenCV from the Git Repository -------------------------------------------------------- - -Launch Git client and clone `OpenCV repository `_. -If you need modules from `OpenCV contrib repository `_ then clone it too. - -For example - -.. code-block:: bash - - cd ~/ - git clone https://github.com/Itseez/opencv.git - git clone https://github.com/Itseez/opencv_contrib.git - -Building OpenCV from Source Using CMake -======================================= - -#. Create a temporary directory, which we denote as , where you want to put the generated Makefiles, project files as well the object files and output binaries and enter there. - - For example - - .. code-block:: bash - - cd ~/opencv - mkdir build - cd build - -#. Configuring. Run - cmake [] - - For example - - .. code-block:: bash - - cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local .. - - or cmake-gui - - * set full path to OpenCV source code, e.g. /home/user/opencv - * set full path to , e.g. /home/user/opencv/build - * set optional parameters - * run: “Configure†- * run: “Generate†- -#. Description of some parameters - - * build type: CMAKE_BUILD_TYPE=Release\\Debug - * to build with modules from opencv_contrib set OPENCV_EXTRA_MODULES_PATH to - * set BUILD_DOCS for building documents - * set BUILD_EXAMPLES to build all examples - -#. [optional] Building python. Set the following python parameters: - - * PYTHON2(3)_EXECUTABLE = - * PYTHON_INCLUDE_DIR = /usr/include/python - * PYTHON_INCLUDE_DIR2 = /usr/include/x86_64-linux-gnu/python - * PYTHON_LIBRARY = /usr/lib/x86_64-linux-gnu/libpython.so - * PYTHON2(3)_NUMPY_INCLUDE_DIRS = /usr/lib/python/dist-packages/numpy/core/include/ - -#. [optional] Building java. - - * Unset parameter: BUILD_SHARED_LIBS - * It is useful also to unset BUILD_EXAMPLES, BUILD_TESTS, BUILD_PERF_TESTS - as they all will be statically linked with OpenCV and can take a lot of memory. - -#. Build. From build directory execute make, recomend to do it in several threads - - For example - - .. code-block:: bash - - make -j7 # runs 7 jobs in parallel - -#. [optional] Building documents. Enter and run make with target "html_docs" - - For example - - .. code-block:: bash - - cd ~/opencv/build/doc/ - make -j7 html_docs - -#. To install libraries, from build directory execute - - .. code-block:: bash - - sudo make install - -#. [optional] Running tests - - * Get the required test data from `OpenCV extra repository `_. - - For example - - .. code-block:: bash - - git clone https://github.com/Itseez/opencv_extra.git - - * set OPENCV_TEST_DATA_PATH environment variable to . - - * execute tests from build directory. - - For example - - .. code-block:: bash - - /bin/opencv_test_core - -.. note:: - - If the size of the created library is a critical issue (like in case of an Android build) you can use the ``install/strip`` command to get the smallest size as possible. The *stripped* version appears to be twice as small. However, we do not recommend using this unless those extra megabytes do really matter. diff --git a/doc/tutorials/introduction/load_save_image/load_save_image.rst b/doc/tutorials/introduction/load_save_image/load_save_image.rst deleted file mode 100644 index 1f494360e3..0000000000 --- a/doc/tutorials/introduction/load_save_image/load_save_image.rst +++ /dev/null @@ -1,117 +0,0 @@ -.. _Load_Save_Image: - -Load, Modify, and Save an Image -******************************* - -.. note:: - - We assume that by now you know how to load an image using :readwriteimage:`imread ` and to display it in a window (using :user_interface:`imshow `). Read the :ref:`Display_Image` tutorial otherwise. - -Goals -====== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Load an image using :readwriteimage:`imread ` - * Transform an image from BGR to Grayscale format by using :miscellaneous_transformations:`cvtColor ` - * Save your transformed image in a file on disk (using :readwriteimage:`imwrite `) - -Code -====== - -Here it is: - -.. code-block:: cpp - :linenos: - - #include - - using namespace cv; - - int main( int argc, char** argv ) - { - char* imageName = argv[1]; - - Mat image; - image = imread( imageName, 1 ); - - if( argc != 2 || !image.data ) - { - printf( " No image data \n " ); - return -1; - } - - Mat gray_image; - cvtColor( image, gray_image, COLOR_BGR2GRAY ); - - imwrite( "../../images/Gray_Image.jpg", gray_image ); - - namedWindow( imageName, WINDOW_AUTOSIZE ); - namedWindow( "Gray image", WINDOW_AUTOSIZE ); - - imshow( imageName, image ); - imshow( "Gray image", gray_image ); - - waitKey(0); - - return 0; - } - -Explanation -============ - -#. We begin by loading an image using :readwriteimage:`imread `, located in the path given by *imageName*. For this example, assume you are loading a RGB image. - -#. Now we are going to convert our image from BGR to Grayscale format. OpenCV has a really nice function to do this kind of transformations: - - .. code-block:: cpp - - cvtColor( image, gray_image, COLOR_BGR2GRAY ); - - As you can see, :miscellaneous_transformations:`cvtColor ` takes as arguments: - - .. container:: enumeratevisibleitemswithsquare - - * a source image (*image*) - * a destination image (*gray_image*), in which we will save the converted image. - * an additional parameter that indicates what kind of transformation will be performed. In this case we use **COLOR_BGR2GRAY** (because of :readwriteimage:`imread ` has BGR default channel order in case of color images). - -#. So now we have our new *gray_image* and want to save it on disk (otherwise it will get lost after the program ends). To save it, we will use a function analagous to :readwriteimage:`imread `: :readwriteimage:`imwrite ` - - .. code-block:: cpp - - imwrite( "../../images/Gray_Image.jpg", gray_image ); - - Which will save our *gray_image* as *Gray_Image.jpg* in the folder *images* located two levels up of my current location. - -#. Finally, let's check out the images. We create two windows and use them to show the original image as well as the new one: - - .. code-block:: cpp - - namedWindow( imageName, WINDOW_AUTOSIZE ); - namedWindow( "Gray image", WINDOW_AUTOSIZE ); - - imshow( imageName, image ); - imshow( "Gray image", gray_image ); - -#. Add the *waitKey(0)* function call for the program to wait forever for an user key press. - - -Result -======= - -When you run your program you should get something like this: - - .. image:: images/Load_Save_Image_Result_1.jpg - :alt: Load Save Image Result 1 - :align: center - -And if you check in your folder (in my case *images*), you should have a newly .jpg file named *Gray_Image.jpg*: - - .. image:: images/Load_Save_Image_Result_2.jpg - :alt: Load Save Image Result 2 - :align: center - -Congratulations, you are done with this tutorial! diff --git a/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.markdown b/doc/tutorials/introduction/table_of_content_introduction.markdown similarity index 100% rename from doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.markdown rename to doc/tutorials/introduction/table_of_content_introduction.markdown diff --git a/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst b/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst deleted file mode 100644 index 78c89ea079..0000000000 --- a/doc/tutorials/introduction/table_of_content_introduction/table_of_content_introduction.rst +++ /dev/null @@ -1,319 +0,0 @@ -.. _Table-Of-Content-Introduction: - -Introduction to OpenCV ------------------------------------------------------------ - -Here you can read tutorials about how to set up your computer to work with the OpenCV library. -Additionally you can find very basic sample source code to introduce you to the -world of the OpenCV. - -.. include:: ../../definitions/tocDefinitions.rst - -* **Linux** - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |Install_1| **Title:** :ref:`Linux-Installation` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to setup OpenCV in your computer! - - =========== ====================================================== - - .. |Install_1| image:: images/ubuntu-logo.jpg - :height: 90pt - :width: 90pt - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |Usage_1| **Title:** :ref:`Linux_GCC_Usage` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to compile your first project using gcc and CMake - - =========== ====================================================== - - .. |Usage_1| image:: images/gccegg-65.jpg - :height: 90pt - :width: 90pt - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |Usage_2| **Title:** :ref:`Linux_Eclipse_Usage` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to compile your first project using the Eclipse environment - - =========== ====================================================== - - .. |Usage_2| image:: images/eclipse_cpp_logo.jpeg - :height: 90pt - :width: 90pt - -* **Windows** - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |WinInstal| **Title:** :ref:`Windows_Installation` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - You will learn how to setup OpenCV in your Windows Operating System! - - =========== ====================================================== - - .. |WinInstal| image:: images/windows_logo.jpg - :height: 90pt - :width: 90pt - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |WinVSHowT| **Title:** :ref:`Windows_Visual_Studio_How_To` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_BernatG| - - You will learn what steps you need to perform in order to use the OpenCV library inside a new Microsoft Visual Studio project. - - =========== ====================================================== - - .. |WinVSHowT| image:: images/visual-studio-2010-logo.jpg - :height: 90pt - :width: 90pt - - =========== ====================================================== - |WinVSVis| **Title:** :ref:`Windows_Visual_Studio_Image_Watch` - - *Compatibility:* >= OpenCV 2.4 - - *Author:* Wolf Kienzle - - You will learn how to visualize OpenCV matrices and images within Visual Studio 2012. - - =========== ====================================================== - - .. |WinVSVis| image:: images/visual_studio_image_watch.png - :height: 90pt - :width: 90pt - -* **Desktop Java** - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ================ ================================================= - |JavaLogo| **Title:** :ref:`Java_Dev_Intro` - - *Compatibility:* > OpenCV 2.4.4 - - *Authors:* |Author_EricCh| and |Author_AndreyP| - - Explains how to build and run a simple desktop Java application using Eclipse, Ant or the Simple Build Tool (SBT). - - ================ ================================================= - - .. |JavaLogo| image:: images/Java_logo.png - :height: 90pt - :width: 90pt - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ================ ================================================= - |EclipseLogo| **Title:** :ref:`Java_Eclipse` - - *Compatibility:* > OpenCV 2.4.4 - - *Author:* |Author_BarisD| - - A tutorial on how to use OpenCV Java with Eclipse. - - ================ ================================================= - - .. |EclipseLogo| image:: images/eclipse-logo.png - :height: 90pt - :width: 90pt - - ================ ================================================= - |ClojureLogo| **Title:** :ref:`clojure_dev_intro` - - *Compatibility:* > OpenCV 2.4.4 - - *Author:* |Author_MimmoC| - - A tutorial on how to interactively use OpenCV from the Clojure REPL. - - ================ ================================================= - - .. |ClojureLogo| image:: images/clojure-logo.png - :height: 90pt - :width: 90pt - -* **Android** - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ================ ================================================= - |AndroidLogo| **Title:** :ref:`Android_Dev_Intro` - - *Compatibility:* > OpenCV 2.4.2 - - *Author:* |Author_VsevolodG| - - Not a tutorial, but a guide introducing Android development basics and environment setup - - ================ ================================================= - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ================ ================================================= - |AndroidLogo| **Title:** :ref:`O4A_SDK` - - *Compatibility:* > OpenCV 2.4.2 - - *Author:* |Author_VsevolodG| - - OpenCV4Android SDK: general info, installation, running samples - - ================ ================================================= - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ================ ================================================= - |AndroidLogo| **Title:** :ref:`dev_with_OCV_on_Android` - - *Compatibility:* > OpenCV 2.4.3 - - *Author:* |Author_VsevolodG| - - Development with OpenCV4Android SDK - - ================ ================================================= - - .. |AndroidLogo| image:: images/android_logo.png - :height: 90pt - :width: 90pt - - -* **iOS** - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============= ====================================================== - |Install_iOS| **Title:** :ref:`iOS-Installation` - - *Compatibility:* > OpenCV 2.4.2 - - *Author:* |Author_ArtemM|, |Author_EduardF| - - We will learn how to setup OpenCV for using it in iOS! - - ============= ====================================================== - - .. |Install_iOS| image:: images/opencv_ios.png - :width: 90pt - -* **Embedded Linux** - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ====================================================== - |Usage_1| **Title:** :ref:`ARM-Linux-cross-compile` - - *Compatibility:* > OpenCV 2.4.4 - - *Author:* |Author_AlexS| - - We will learn how to setup OpenCV cross compilation environment for ARM Linux. - - =========== ====================================================== - -* **Common** - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============= ====================================================== - |Beginners_1| **Title:** :ref:`Display_Image` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to display an image using OpenCV - - ============= ====================================================== - - .. |Beginners_1| image:: images/Display_Image_Tutorial_Result.jpg - :height: 90pt - :width: 90pt - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =============== ====================================================== - |Beginners_2| **Title:** :ref:`Load_Save_Image` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - We will learn how to save an Image in OpenCV...plus a small conversion to grayscale - - =============== ====================================================== - - .. |Beginners_2| image:: images/Load_Save_Image_Result_1.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it. -.. toctree:: - :hidden: - - ../linux_install/linux_install - ../linux_gcc_cmake/linux_gcc_cmake - ../linux_eclipse/linux_eclipse - ../windows_install/windows_install - ../windows_visual_studio_Opencv/windows_visual_studio_Opencv - ../windows_visual_studio_image_watch/windows_visual_studio_image_watch - ../desktop_java/java_dev_intro - ../java_eclipse/java_eclipse - ../clojure_dev_intro/clojure_dev_intro - ../android_binary_package/android_dev_intro - ../android_binary_package/O4A_SDK - ../android_binary_package/dev_with_OCV_on_Android - ../ios_install/ios_install - ../crosscompilation/arm_crosscompile_with_cmake - ../display_image/display_image - ../load_save_image/load_save_image diff --git a/doc/tutorials/introduction/windows_install/windows_install.rst b/doc/tutorials/introduction/windows_install/windows_install.rst deleted file mode 100644 index 8d31336df6..0000000000 --- a/doc/tutorials/introduction/windows_install/windows_install.rst +++ /dev/null @@ -1,345 +0,0 @@ -.. _Windows_Installation: - -Installation in Windows -*********************** - -.. include:: - -The description here was tested on Windows 7 SP1. Nevertheless, it should also work on any other relatively modern version of Windows OS. If you encounter errors after following the steps described below, feel free to contact us via our `OpenCV Q&A forum `_. We'll do our best to help you out. - -.. note:: To use the OpenCV library you have two options: :ref:`Windows_Install_Prebuild` or :ref:`CppTutWindowsMakeOwn`. While the first one is easier to complete, it only works if you are coding with the latest Microsoft Visual Studio IDE and doesn't take advantage of the most advanced technologies we integrate into our library. - -.. _Windows_Install_Prebuild: - -Installation by Using the Pre-built Libraries -============================================= - -#. Launch a web browser of choice and go to our `page on Sourceforge `_. - -#. Choose a build you want to use and download it. - - .. If you downloaded the source files present here see :ref:`CppTutWindowsMakeOwn`. - -#. Make sure you have admin rights. Unpack the self-extracting archive. - -#. You can check the installation at the chosen path as you can see below. - - .. image:: images/OpenCV_Install_Directory.png - :alt: An example of how the installation directory should look in case of successful install. - :align: center - -#. To finalize the installation go to the :ref:`WindowsSetPathAndEnviromentVariable` section. - -.. _CppTutWindowsMakeOwn: - -Installation by Making Your Own Libraries from the Source Files -=============================================================== - -You may find the content of this tutorial also inside the following videos: `Part 1 `_ and `Part 2 `_, hosted on YouTube. - -.. raw:: html - -
- - -
- -.. warning:: These videos above are long-obsolete and contain inaccurate information. Be careful, since solutions described in those videos are no longer supported and may even break your install. - -If you are building your own libraries you can take the source files from our `Git repository `_. - -Building the OpenCV library from scratch requires a couple of tools installed beforehand: - -.. |CMake| replace:: CMake -.. _CMake: http://www.cmake.org/cmake/resources/software.html -.. |TortoiseGit| replace:: TortoiseGit -.. _TortoiseGit: http://code.google.com/p/tortoisegit/wiki/Download -.. |Python_Libraries| replace:: Python libraries -.. _Python_Libraries: http://www.python.org/downloads/ -.. |Numpy| replace:: Numpy -.. _Numpy: http://numpy.scipy.org/ -.. |IntelTBB| replace:: Intel |copy| Threading Building Blocks (*TBB*) -.. _IntelTBB: http://threadingbuildingblocks.org/file.php?fid=77 -.. |IntelIIP| replace:: Intel |copy| Integrated Performance Primitives (*IPP*) -.. _IntelIIP: http://software.intel.com/en-us/articles/intel-ipp/ -.. |IntelIIPA| replace:: Intel |copy| IPP Asynchronous C/C++ -.. _IntelIIPA: http://software.intel.com/en-us/intel-ipp-preview -.. |qtframework| replace:: Qt framework -.. _qtframework: http://qt.nokia.com/downloads -.. |Eigen| replace:: Eigen -.. _Eigen: http://eigen.tuxfamily.org/index.php?title=Main_Page#Download -.. |CUDA_Toolkit| replace:: CUDA Toolkit -.. _CUDA_Toolkit: http://developer.nvidia.com/cuda-downloads -.. |OpenEXR| replace:: OpenEXR -.. _OpenEXR: http://www.openexr.com/downloads.html -.. |OpenNI_Framework| replace:: OpenNI Framework -.. _OpenNI_Framework: http://www.openni.org/ -.. |Miktex| replace:: Miktex -.. _Miktex: http://miktex.org/2.9/setup -.. |Sphinx| replace:: Sphinx -.. _Sphinx: http://sphinx.pocoo.org/ - -.. container:: enumeratevisibleitemswithsquare - - + An IDE of choice (preferably), or just a C\C++ compiler that will actually make the binary files. Here we will use the `Microsoft Visual Studio `_. However, you can use any other IDE that has a valid C\C++ compiler. - - + |CMake|_, which is a neat tool to make the project files (for your chosen IDE) from the OpenCV source files. It will also allow an easy configuration of the OpenCV build files, in order to make binary files that fits exactly to your needs. - - + Git to acquire the OpenCV source files. A good tool for this is |TortoiseGit|_. Alternatively, you can just download an archived version of the source files from our `page on Sourceforge `_ - -OpenCV may come in multiple flavors. There is a "core" section that will work on its own. Nevertheless, there is a couple of tools, libraries made by 3rd parties that offer services of which the OpenCV may take advantage. These will improve its capabilities in many ways. In order to use any of them, you need to download and install them on your system. - -.. container:: enumeratevisibleitemswithsquare - - + The |Python_Libraries|_ are required to build the *Python interface* of OpenCV. For now use the version :file:`2.7.{x}`. This is also a must if you want to build the *OpenCV documentation*. - - + |Numpy|_ is a scientific computing package for Python. Required for the *Python interface*. - - + |IntelTBB|_ is used inside OpenCV for parallel code snippets. Using this will make sure that the OpenCV library will take advantage of all the cores you have in your systems CPU. - - + |IntelIIP|_ may be used to improve the performance of color conversion, Haar training and DFT functions of the OpenCV library. Watch out, since this isn't a free service. - - + |IntelIIPA|_ is currently focused delivering Intel |copy| Graphics support for advanced image processing and computer vision functions. - - + OpenCV offers a somewhat fancier and more useful graphical user interface, than the default one by using the |qtframework|_. For a quick overview of what this has to offer look into the documentations *highgui* module, under the *Qt New Functions* section. Version 4.6 or later of the framework is required. - - + |Eigen|_ is a C++ template library for linear algebra. - - + The latest |CUDA_Toolkit|_ will allow you to use the power lying inside your GPU. This will drastically improve performance for some algorithms (e.g the HOG descriptor). Getting more and more of our algorithms to work on the GPUs is a constant effort of the OpenCV team. - - + |OpenEXR|_ source files are required for the library to work with this high dynamic range (HDR) image file format. - - + The |OpenNI_Framework|_ contains a set of open source APIs that provide support for natural interaction with devices via methods such as voice command recognition, hand gestures and body motion tracking. - - + |Miktex|_ is the best `TEX `_ implementation on the Windows OS. It is required to build the *OpenCV documentation*. - - + |Sphinx|_ is a python documentation generator and is the tool that will actually create the *OpenCV documentation*. This on its own requires a couple of tools installed, We will cover this in depth at the :ref:`How to Install Sphinx ` section. - -Now we will describe the steps to follow for a full build (using all the above frameworks, tools and libraries). If you do not need the support for some of these you can just freely skip this section. - -.. _WindowsBuildLibrary: - -Building the library -^^^^^^^^^^^^^^^^^^^^ - -1. Make sure you have a working IDE with a valid compiler. In case of the Microsoft Visual Studio just install it and make sure it starts up. - -#. Install |CMake|_. Simply follow the wizard, no need to add it to the path. The default install options are OK. - -#. Download and install an up-to-date version of msysgit from its `official site `_. There is also the portable version, which you need only to unpack to get access to the console version of Git. Supposing that for some of us it could be quite enough. - -#. Install |TortoiseGit|_. Choose the 32 or 64 bit version according to the type of OS you work in. While installing, locate your msysgit (if it doesn't do that automatically). Follow the wizard -- the default options are OK for the most part. - -#. Choose a directory in your file system, where you will download the OpenCV libraries to. I recommend creating a new one that has short path and no special charachters in it, for example :file:`D:/OpenCV`. For this tutorial I'll suggest you do so. If you use your own path and know, what you're doing -- it's OK. - - a) Clone the repository to the selected directory. After clicking *Clone* button, a window will appear where you can select from what repository you want to download source files (https://github.com/Itseez/opencv.git) and to what directory (:file:`D:/OpenCV`). - - #) Push the OK button and be patient as the repository is quite a heavy download. It will take some time depending on your Internet connection. - -#. In this section I will cover installing the 3rd party libraries. - - a) Download the |Python_Libraries|_ and install it with the default options. You will need a couple other python extensions. Luckily installing all these may be automated by a nice tool called `Setuptools `_. Download and install again. - - #) .. _HereInstallSphinx: - - Installing Sphinx is easy once you have installed *Setuptools*. This contains a little application that will automatically connect to the python databases and download the latest version of many python scripts. Start up a command window (enter *cmd* into the windows start menu and press enter) and use the *CD* command to navigate to your Python folders Script sub-folder. Here just pass to the *easy_install.exe* as argument the name of the program you want to install. Add the *sphinx* argument. - - .. image:: images/cmsdstartwindows.jpg - :alt: The Windows Command Startup - :align: center - - .. image:: images/Sphinx_Install.png - :alt: How to start the command window - :align: center - - .. note:: - - The *CD* navigation command works only inside a drive. For example if you are somewhere in the *C:* drive you cannot use it this to go to another drive (like for example *D:*). To do so you first need to change drives letters. For this simply enter the command *D:*. Then you can use the *CD* to navigate to specific folder inside the drive. Bonus tip: you can clear the screen by using the *CLS* command. - - This will also install its prerequisites `Jinja2 `_ and `Pygments `_. - - #) The easiest way to install |Numpy|_ is to just download its binaries from the `sourceforga page `_. Make sure your download and install exactly the binary for your python version (so for version :file:`2.7`). - - #) Download the |Miktex|_ and install it. Again just follow the wizard. At the fourth step make sure you select for the *"Install missing packages on-the-fly"* the *Yes* option, as you can see on the image below. Again this will take quite some time so be patient. - - .. image:: images/MiktexInstall.png - :alt: The Miktex Install Screen - :align: center - - #) For the |IntelTBB|_ download the source files and extract it inside a directory on your system. For example let there be :file:`D:/OpenCV/dep`. For installing the |IntelIIP|_ the story is the same. For exctracting the archives I recommend using the `7-Zip `_ application. - - .. image:: images/IntelTBB.png - :alt: The Miktex Install Screen - :align: center - - #) For the |IntelIIPA|_ download the source files and set environment variable **IPP_ASYNC_ROOT**. It should point to :file:`/Intel/IPP Preview */ipp directory`. Here ``*`` denotes the particular preview name. - - #) In case of the |Eigen|_ library it is again a case of download and extract to the :file:`D:/OpenCV/dep` directory. - - #) Same as above with |OpenEXR|_. - - #) For the |OpenNI_Framework|_ you need to install both the `development build `_ and the `PrimeSensor Module `_. - - #) For the CUDA you need again two modules: the latest |CUDA_Toolkit|_ and the *CUDA Tools SDK*. Download and install both of them with a *complete* option by using the 32 or 64 bit setups according to your OS. - - #) In case of the |qtframework|_ you need to build yourself the binary files (unless you use the Microsoft Visual Studio 2008 with 32 bit compiler). To do this go to the `Qt Downloads `_ page. Download the source files (not the installers!!!): - - .. image:: images/qtDownloadThisPackage.png - :alt: Download this Qt Package - :align: center - - Extract it into a nice and short named directory like :file:`D:/OpenCV/dep/qt/` . - Then you need to build it. Start up a *Visual* *Studio* *Command* *Prompt* (*2010*) by using the start menu search (or navigate through the start menu :menuselection:`All Programs --> Microsoft Visual Studio 2010 --> Visual Studio Tools --> Visual Studio Command Prompt (2010)`). - - .. image:: images/visualstudiocommandprompt.jpg - :alt: The Visual Studio command prompt - :align: center - - Now navigate to the extracted folder and enter inside it by using this console window. You should have a folder containing files like *Install*, *Make* and so on. Use the *dir* command to list files inside your current directory. Once arrived at this directory enter the following command: - - .. code-block:: bash - - configure.exe -release -no-webkit -no-phonon -no-phonon-backend -no-script -no-scripttools - -no-qt3support -no-multimedia -no-ltcg - - Completing this will take around 10-20 minutes. Then enter the next command that will take a lot longer (can easily take even more than a full hour): - - .. code-block:: bash - - nmake - - After this set the Qt enviroment variables using the following command on Windows 7: - - .. code-block:: bash - - setx -m QTDIR D:/OpenCV/dep/qt/qt-everywhere-opensource-src-4.7.3 - - .. |PathEditor| replace:: Path Editor - .. _PathEditor: http://www.redfernplace.com/software-projects/patheditor/ - - Also, add the built binary files path to the system path by using the |PathEditor|_. In our case this is :file:`D:/OpenCV/dep/qt/qt-everywhere-opensource-src-4.7.3/bin`. - - .. note:: - - If you plan on doing Qt application development you can also install at this point the *Qt Visual Studio Add-in*. After this you can make and build Qt applications without using the *Qt Creator*. Everything is nicely integrated into Visual Studio. - -#. Now start the *CMake (cmake-gui)*. You may again enter it in the start menu search or get it from the :menuselection:`All Programs --> CMake 2.8 --> CMake (cmake-gui)`. First, select the directory for the source files of the OpenCV library (1). Then, specify a directory where you will build the binary files for OpenCV (2). - - .. image:: images/CMakeSelectBin.jpg - :alt: Select the directories - :align: center - - Press the Configure button to specify the compiler (and *IDE*) you want to use. Note that in case you can choose between different compilers for making either 64 bit or 32 bit libraries. Select the one you use in your application development. - - .. image:: images/CMake_Configure_Windows.jpg - :alt: How CMake should look at build time. - :align: center - - CMake will start out and based on your system variables will try to automatically locate as many packages as possible. You can modify the packages to use for the build in the :menuselection:`WITH --> WITH_X` menu points (where *X* is the package abbreviation). Here are a list of current packages you can turn on or off: - - .. image:: images/CMakeBuildWithWindowsGUI.jpg - :alt: The packages OpenCV may use - :align: center - - Select all the packages you want to use and press again the *Configure* button. For an easier overview of the build options make sure the *Grouped* option under the binary directory selection is turned on. For some of the packages CMake may not find all of the required files or directories. In case of these CMake will throw an error in its output window (located at the bottom of the GUI) and set its field values, to not found constants. For example: - - .. image:: images/CMakePackageNotFoundWindows.jpg - :alt: Constant for not found packages - :align: center - - .. image:: images/CMakeOutputPackageNotFound.jpg - :alt: Error (warning) thrown in output window of the CMake GUI - :align: center - - For these you need to manually set the queried directories or files path. After this press again the *Configure* button to see if the value entered by you was accepted or not. Do this until all entries are good and you cannot see errors in the field/value or the output part of the GUI. - Now I want to emphasize an option that you will definitely love: :menuselection:`ENABLE --> ENABLE_SOLUTION_FOLDERS`. OpenCV will create many-many projects and turning this option will make sure that they are categorized inside directories in the *Solution Explorer*. It is a must have feature, if you ask me. - - .. image:: images/CMakeBuildOptionsOpenCV.jpg - :alt: Set the Solution Folders and the parts you want to build - :align: center - - Furthermore, you need to select what part of OpenCV you want to build. - - .. container:: enumeratevisibleitemswithsquare - - + *BUILD_DOCS* -> It creates two projects for building the documentation of OpenCV (there will be a separate project for building the HTML and the PDF files). Note that these aren't built together with the solution. You need to make an explicit build project command on these to do so. - + *BUILD_EXAMPLES* -> OpenCV comes with many example applications from which you may learn most of the libraries capabilities. This will also come handy to easily try out if OpenCV is fully functional on your computer. - + *BUILD_PACKAGE* -> Prior to version 2.3 with this you could build a project that will build an OpenCV installer. With this you can easily install your OpenCV flavor on other systems. For the latest source files of OpenCV it generates a new project that simply creates zip archive with OpenCV sources. - + *BUILD_SHARED_LIBS* -> With this you can control to build DLL files (when turned on) or static library files (\*.lib) otherwise. - + *BUILD_TESTS* -> Each module of OpenCV has a test project assigned to it. Building these test projects is also a good way to try out, that the modules work just as expected on your system too. - + *BUILD_PERF_TESTS* -> There are also performance tests for many OpenCV functions. If you're concerned about performance, build them and run. - + *BUILD_opencv_python* -> Self-explanatory. Create the binaries to use OpenCV from the Python language. - - Press again the *Configure* button and ensure no errors are reported. If this is the case you can tell CMake to create the project files by pushing the *Generate* button. Go to the build directory and open the created **OpenCV** solution. - Depending on just how much of the above options you have selected the solution may contain quite a lot of projects so be tolerant on the IDE at the startup. - Now you need to build both the *Release* and the *Debug* binaries. Use the drop-down menu on your IDE to change to another of these after building for one of them. - - .. image:: images/ChangeBuildVisualStudio.jpg - :alt: Look here for changing the Build Type - :align: center - - In the end you can observe the built binary files inside the bin directory: - - .. image:: images/OpenCVBuildResultWindows.jpg - :alt: The Result of the build. - :align: center - - For the documentation you need to explicitly issue the build commands on the *doc* project for the PDF files and on the *doc_html* for the HTML ones. Each of these will call *Sphinx* to do all the hard work. You can find the generated documentation inside the :file:`Build/Doc/_html` for the HTML pages and within the :file:`Build/Doc` the PDF manuals. - - .. image:: images/WindowsBuildDoc.png - :alt: The Documentation Projects - :align: center - - To collect the header and the binary files, that you will use during your own projects, into a separate directory (simillary to how the pre-built binaries ship) you need to explicitely build the *Install* project. - - .. image:: images/WindowsBuildInstall.png - :alt: The Install Project - :align: center - - This will create an *Install* directory inside the *Build* one collecting all the built binaries into a single place. Use this only after you built both the *Release* and *Debug* versions. - - To test your build just go into the :file:`Build/bin/Debug` or :file:`Build/bin/Release` directory and start a couple of applications like the *contours.exe*. If they run, you are done. Otherwise, something definitely went awfully wrong. In this case you should contact us at our :opencv_qa:`Q&A forum <>`. - If everything is okay the *contours.exe* output should resemble the following image (if built with Qt support): - - .. image:: images/WindowsQtContoursOutput.png - :alt: A good output result - :align: center - - .. note:: - - If you use the GPU module (CUDA libraries) make sure you also upgrade to the latest drivers of your GPU. Error messages containing invalid entries in (or cannot find) the nvcuda.dll are caused mostly by old video card drivers. For testing the GPU (if built) run the *performance_gpu.exe* sample application. - -.. _WindowsSetPathAndEnviromentVariable: - -Set the OpenCV enviroment variable and add it to the systems path -================================================================= - -First we set an enviroment variable to make easier our work. This will hold the build directory of our OpenCV library that we use in our projects. Start up a command window and enter: - -:: - - setx -m OPENCV_DIR D:\OpenCV\Build\x86\vc10 (suggested for Visual Studio 2010 - 32 bit Windows) - setx -m OPENCV_DIR D:\OpenCV\Build\x64\vc10 (suggested for Visual Studio 2010 - 64 bit Windows) - - setx -m OPENCV_DIR D:\OpenCV\Build\x86\vc11 (suggested for Visual Studio 2012 - 32 bit Windows) - setx -m OPENCV_DIR D:\OpenCV\Build\x64\vc11 (suggested for Visual Studio 2012 - 64 bit Windows) - -Here the directory is where you have your OpenCV binaries (*extracted* or *built*). You can have different platform (e.g. x64 instead of x86) or compiler type, so substitute appropriate value. Inside this you should have two folders called *lib* and *bin*. The -m should be added if you wish to make the settings computer wise, instead of user wise. - -If you built static libraries then you are done. Otherwise, you need to add the *bin* folders path to the systems path. This is because you will use the OpenCV library in form of *\"Dynamic-link libraries\"* (also known as **DLL**). Inside these are stored all the algorithms and information the OpenCV library contains. The operating system will load them only on demand, during runtime. However, to do this the operating system needs to know where they are. The systems **PATH** contains a list of folders where DLLs can be found. Add the OpenCV library path to this and the OS will know where to look if he ever needs the OpenCV binaries. Otherwise, you will need to copy the used DLLs right beside the applications executable file (*exe*) for the OS to find it, which is highly unpleasent if you work on many projects. To do this start up again the |PathEditor|_ and add the following new entry (right click in the application to bring up the menu): - -:: - - %OPENCV_DIR%\bin - -.. image:: images/PathEditorOpenCVInsertNew.png - :alt: Right click to insert new path manually. - :align: center - -.. image:: images/PathEditorOpenCVSetPath.png - :alt: Add the entry. - :align: center - -Save it to the registry and you are done. If you ever change the location of your build directories or want to try out your applicaton with a different build all you will need to do is to update the OPENCV_DIR variable via the *setx* command inside a command window. - -Now you can continue reading the tutorials with the :ref:`Windows_Visual_Studio_How_To` section. There you will find out how to use the OpenCV library in your own projects with the help of the Microsoft Visual Studio IDE. diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.markdown b/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.markdown index 753fc7ac8f..f8b78f0117 100644 --- a/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.markdown +++ b/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.markdown @@ -189,12 +189,11 @@ Test it! -------- Now to try this out download our little test [source code -](samples/cpp/tutorial_code/introduction/windows_visual_studio_Opencv/introduction_windows_vs.cpp) +](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/introduction/windows_visual_studio_Opencv/introduction_windows_vs.cpp) or get it from the sample code folder of the OpenCV sources. Add this to your project and build it. Here's its content: -@includelineno -cpp/tutorial_code/introduction/windows_visual_studio_Opencv/introduction_windows_vs.cpp +@includelineno cpp/tutorial_code/introduction/windows_visual_studio_Opencv/introduction_windows_vs.cpp You can start a Visual Studio build from two places. Either inside from the *IDE* (keyboard combination: Control-F5) or by navigating to your build directory and start the application with a @@ -206,7 +205,7 @@ the *IDE* the console window will not close once finished. It will wait for a ke This is important to remember when you code inside the code open and save commands. You're resources will be saved ( and queried for at opening!!!) relatively to your working directory. This is unless you give a full, explicit path as parameter for the I/O functions. In the code above we open [this -OpenCV logo](samples/data/opencv-logo.png). Before starting up the application make sure you place +OpenCV logo](https://github.com/Itseez/opencv/tree/master/samples/data/opencv-logo.png). Before starting up the application make sure you place the image file in your current working directory. Modify the image file name inside the code to try it out on other images too. Run it and voil á: diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.rst b/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.rst deleted file mode 100644 index 26ce913fba..0000000000 --- a/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.rst +++ /dev/null @@ -1,187 +0,0 @@ -.. _Windows_Visual_Studio_How_To: - -How to build applications with OpenCV inside the *Microsoft Visual Studio* -************************************************************************** - -Everything I describe here will apply to the C\\C++ interface of OpenCV. -I start out from the assumption that you have read and completed with success the :ref:`Windows_Installation` tutorial. Therefore, before you go any further make sure you have an OpenCV directory that contains the OpenCV header files plus binaries and you have set the environment variables as :ref:`described here `. - -.. image:: images/OpenCV_Install_Directory.jpg - :alt: You should have a folder looking like this. - :align: center - -The OpenCV libraries, distributed by us, on the Microsoft Windows operating system are in a **D**\ ynamic **L**\ inked **L**\ ibraries (*DLL*). These have the advantage that all the content of the library are loaded only at runtime, on demand, and that countless programs may use the same library file. This means that if you have ten applications using the OpenCV library, no need to have around a version for each one of them. Of course you need to have the *dll* of the OpenCV on all systems where you want to run your application. - -Another approach is to use static libraries that have *lib* extensions. You may build these by using our source files as described in the :ref:`Windows_Installation` tutorial. When you use this the library will be built-in inside your *exe* file. So there is no chance that the user deletes them, for some reason. As a drawback your application will be larger one and as, it will take more time to load it during its startup. - -To build an application with OpenCV you need to do two things: - -.. container:: enumeratevisibleitemswithsquare - - + *Tell* to the compiler how the OpenCV library *looks*. You do this by *showing* it the header files. - + *Tell* to the linker from where to get the functions or data structures of OpenCV, when they are needed. - - If you use the *lib* system you must set the path where the library files are and specify in which one of them to look. During the build the linker will look into these libraries and add the definitions and implementation of all *used* functions and data structures to the executable file. - - If you use the *DLL* system you must again specify all this, however now for a different reason. This is a Microsoft OS specific stuff. It seems that the linker needs to know that where in the DLL to search for the data structure or function at the runtime. This information is stored inside *lib* files. Nevertheless, they aren't static libraries. They are so called import libraries. This is why when you make some *DLLs* in Windows you will also end up with some *lib* extension libraries. The good part is that at runtime only the *DLL* is required. - -To pass on all this information to the Visual Studio IDE you can either do it globally (so all your future projects will get these information) or locally (so only for you current project). The advantage of the global one is that you only need to do it once; however, it may be undesirable to clump all your projects all the time with all these information. In case of the global one how you do it depends on the Microsoft Visual Studio you use. There is a **2008 and previous versions** and a **2010 way** of doing it. Inside the global section of this tutorial I'll show what the main differences are. - -The base item of a project in Visual Studio is a solution. A solution may contain multiple projects. Projects are the building blocks of an application. Every project will realize something and you will have a main project in which you can put together this project puzzle. In case of the many simple applications (like many of the tutorials will be) you do not need to break down the application into modules. In these cases your main project will be the only existing one. Now go create a new solution inside Visual studio by going through the :menuselection:`File --> New --> Project` menu selection. Choose *Win32 Console Application* as type. Enter its name and select the path where to create it. Then in the upcoming dialog make sure you create an empty project. - -.. image:: images/NewProjectVisualStudio.jpg - :alt: Which options to select - :align: center - -The *local* method -================== - -Every project is built separately from the others. Due to this every project has its own rule package. Inside this rule packages are stored all the information the *IDE* needs to know to build your project. For any application there are at least two build modes: a *Release* and a *Debug* one. The *Debug* has many features that exist so you can find and resolve easier bugs inside your application. In contrast the *Release* is an optimized version, where the goal is to make the application run as fast as possible or to be as small as possible. You may figure that these modes also require different rules to use during build. Therefore, there exist different rule packages for each of your build modes. These rule packages are called inside the IDE as *project properties* and you can view and modify them by using the *Property Manger*. You can bring up this with :menuselection:`View --> Property Pages`. Expand it and you can see the existing rule packages (called *Proporty Sheets*). - -.. image:: images/PropertyPageExample.jpg - :alt: An example of Property Sheet - :align: center - -The really useful stuff of these is that you may create a rule package *once* and you can later just add it to your new projects. Create it once and reuse it later. We want to create a new *Property Sheet* that will contain all the rules that the compiler and linker needs to know. Of course we will need a separate one for the Debug and the Release Builds. Start up with the Debug one as shown in the image below: - -.. image:: images/AddNewPropertySheet.jpg - :alt: Add a new Property Sheet - :align: center - -Use for example the *OpenCV_Debug* name. Then by selecting the sheet :menuselection:`Right Click --> Properties`. In the following I will show to set the OpenCV rules locally, as I find unnecessary to pollute projects with custom rules that I do not use it. Go the C++ groups General entry and under the *"Additional Include Directories"* add the path to your OpenCV include. If you don't have *"C/C++"* group, you should add any .c/.cpp file to the project. - -.. code-block:: bash - - $(OPENCV_DIR)\..\..\include - -.. image:: images/PropertySheetOpenCVInclude.jpg - :alt: Add the include dir like this. - :align: center - -When adding third party libraries settings it is generally a good idea to use the power behind the environment variables. The full location of the OpenCV library may change on each system. Moreover, you may even end up yourself with moving the install directory for some reason. If you would give explicit paths inside your property sheet your project will end up not working when you pass it further to someone else who has a different OpenCV install path. Moreover, fixing this would require to manually modifying every explicit path. A more elegant solution is to use the environment variables. Anything that you put inside a parenthesis started with a dollar sign will be replaced at runtime with the current environment variables value. Here comes in play the environment variable setting we already made in our :ref:`previous tutorial `. - -Next go to the :menuselection:`Linker --> General` and under the *"Additional Library Directories"* add the libs directory: - -.. code-block:: bash - - $(OPENCV_DIR)\lib - -.. image:: images/PropertySheetOpenCVLib.jpg - :alt: Add the library folder like this. - :align: center - -Then you need to specify the libraries in which the linker should look into. To do this go to the :menuselection:`Linker --> Input` and under the *"Additional Dependencies"* entry add the name of all modules which you want to use: - -.. image:: images/PropertySheetOpenCVLibrariesDebugSmple.jpg - :alt: Add the debug library names here. - :align: center - -.. image:: images/PropertySheetOpenCVLibrariesDebug.jpg - :alt: Like this. - :align: center - -The names of the libraries are as follow: - -.. code-block:: bash - - opencv_(The Name of the module)(The version Number of the library you use)d.lib - -A full list, for the latest version would contain: - -.. code-block:: bash - - opencv_calib3d300d.lib - opencv_core300d.lib - opencv_features2d300d.lib - opencv_flann300d.lib - opencv_highgui300d.lib - opencv_imgcodecs300d.lib - opencv_imgproc300d.lib - opencv_ml300d.lib - opencv_objdetect300d.lib - opencv_photo300d.lib - opencv_shape300d.lib - opencv_stitching300d.lib - opencv_superres300d.lib - opencv_ts300d.lib - opencv_video300d.lib - opencv_videoio300d.lib - opencv_videostab300d.lib - - -The letter *d* at the end just indicates that these are the libraries required for the debug. Now click ok to save and do the same with a new property inside the Release rule section. Make sure to omit the *d* letters from the library names and to save the property sheets with the save icon above them. - -.. image:: images/PropertySheetOpenCVLibrariesRelease.jpg - :alt: And the release ones. - :align: center - -You can find your property sheets inside your projects directory. At this point it is a wise decision to back them up into some special directory, to always have them at hand in the future, whenever you create an OpenCV project. Note that for Visual Studio 2010 the file extension is *props*, while for 2008 this is *vsprops*. - -.. image:: images/PropertySheetInsideFolder.jpg - :alt: And the release ones. - :align: center - -Next time when you make a new OpenCV project just use the "Add Existing Property Sheet..." menu entry inside the Property Manager to easily add the OpenCV build rules. - -.. image:: images/PropertyPageAddExisting.jpg - :alt: Use this option. - :align: center - -The *global* method -=================== - -In case you find to troublesome to add the property pages to each and every one of your projects you can also add this rules to a *"global property page"*. However, this applies only to the additional include and library directories. The name of the libraries to use you still need to specify manually by using for instance: a Property page. - -In Visual Studio 2008 you can find this under the: :menuselection:`Tools --> Options --> Projects and Solutions --> VC++ Directories`. - -.. image:: images/VCDirectories2008.jpg - :alt: VC++ Directories in VS 2008. - :align: center - -In Visual Studio 2010 this has been moved to a global property sheet which is automatically added to every project you create: - -.. image:: images/VCDirectories2010.jpg - :alt: VC++ Directories in VS 2010. - :align: center - -The process is the same as described in case of the local approach. Just add the include directories by using the environment variable *OPENCV_DIR*. - -Test it! -======== - -Now to try this out download our little test :download:`source code <../../../../samples/cpp/tutorial_code/introduction/windows_visual_studio_Opencv/introduction_windows_vs.cpp>` or get it from the sample code folder of the OpenCV sources. Add this to your project and build it. Here's its content: - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/windows_visual_studio_Opencv/introduction_windows_vs.cpp - :language: cpp - :tab-width: 4 - :linenos: - -You can start a Visual Studio build from two places. Either inside from the *IDE* (keyboard combination: :kbd:`Control-F5`) or by navigating to your build directory and start the application with a double click. The catch is that these two **aren't** the same. When you start it from the *IDE* its current working directory is the projects directory, while otherwise it is the folder where the application file currently is (so usually your build directory). Moreover, in case of starting from the *IDE* the console window will not close once finished. It will wait for a keystroke of yours. - -.. |voila| unicode:: voil U+00E1 - -This is important to remember when you code inside the code open and save commands. You're resources will be saved ( and queried for at opening!!!) relatively to your working directory. This is unless you give a full, explicit path as parameter for the I/O functions. In the code above we open :download:`this OpenCV logo<../../../../samples/data/opencv-logo.png>`. Before starting up the application make sure you place the image file in your current working directory. Modify the image file name inside the code to try it out on other images too. Run it and |voila|: - -.. image:: images/SuccessVisualStudioWindows.jpg - :alt: You should have this. - :align: center - -Command line arguments with Visual Studio -========================================= - -Throughout some of our future tutorials you'll see that the programs main input method will be by giving a runtime argument. To do this you can just start up a commmand windows (:kbd:`cmd + Enter` in the start menu), navigate to your executable file and start it with an argument. So for example in case of my upper project this would look like: - -.. code-block:: bash - :linenos: - - D: - CD OpenCV\MySolutionName\Release - MySolutionName.exe exampleImage.jpg - -Here I first changed my drive (if your project isn't on the OS local drive), navigated to my project and start it with an example image argument. While under Linux system it is common to fiddle around with the console window on the Microsoft Windows many people come to use it almost never. Besides, adding the same argument again and again while you are testing your application is, somewhat, a cumbersome task. Luckily, in the Visual Studio there is a menu to automate all this: - -.. image:: images/VisualStudioCommandLineArguments.jpg - :alt: Visual Studio Command Line Arguments - :align: center - -Specify here the name of the inputs and while you start your application from the Visual Studio enviroment you have automatic argument passing. In the next introductionary tutorial you'll see an in-depth explanation of the upper source code: :ref:`Display_Image`. diff --git a/doc/tutorials/introduction/windows_visual_studio_image_watch/windows_visual_studio_image_watch.rst b/doc/tutorials/introduction/windows_visual_studio_image_watch/windows_visual_studio_image_watch.rst deleted file mode 100644 index 72309fa786..0000000000 --- a/doc/tutorials/introduction/windows_visual_studio_image_watch/windows_visual_studio_image_watch.rst +++ /dev/null @@ -1,146 +0,0 @@ -.. _Windows_Visual_Studio_Image_Watch: - -Image Watch: viewing in-memory images in the Visual Studio debugger -******************************************************************* - -Image Watch is a plug-in for Microsoft Visual Studio that lets you to visualize in-memory images (*cv::Mat* or *IplImage\_* objects, for example) while debugging an application. This can be helpful for tracking down bugs, or for simply understanding what a given piece of code is doing. - -Prerequisites -============= - -This tutorial assumes that you have the following available: - -#. Visual Studio 2012 Professional (or better) with Update 1 installed. Update 1 can be downloaded `here `_. - -#. An OpenCV installation on your Windows machine (Tutorial: :ref:`Windows_Installation`). - -#. Ability to create and build OpenCV projects in Visual Studio (Tutorial: :ref:`Windows_Visual_Studio_How_To`). - -Installation -============ - -`Download `_ the Image Watch installer. The installer comes in a single file with extension .vsix (*Visual Studio Extension*). To launch it, simply double-click on the .vsix file in Windows Explorer. When the installer has finished, make sure to restart Visual Studio to complete the installation. - -Example -======== - -Image Watch works with any existing project that uses OpenCV image objects (for example, *cv::Mat*). In this example, we use a minimal test program that loads an image from a file and runs an edge detector. To build the program, create a console application project in Visual Studio, name it "image-watch-demo", and insert the source code below. - -.. code-block:: cpp - - // Test application for the Visual Studio Image Watch Debugger extension - - #include // std::cout - #include // cv::Mat - #include // cv::imread() - #include // cv::Canny() - - using namespace std; - using namespace cv; - - void help() - { - cout - << "----------------------------------------------------" << endl - << "This is a test program for the Image Watch Debugger " << endl - << "plug-in for Visual Studio. The program loads an " << endl - << "image from a file and runs the Canny edge detector. " << endl - << "No output is displayed or written to disk." - << endl - << "Usage:" << endl - << "image-watch-demo inputimage" << endl - << "----------------------------------------------------" << endl - << endl; - } - - int main(int argc, char *argv[]) - { - help(); - - if (argc != 2) - { - cout << "Wrong number of parameters" << endl; - return -1; - } - - cout << "Loading input image: " << argv[1] << endl; - Mat input; - input = imread(argv[1], IMREAD_COLOR); - - cout << "Detecting edges in input image" << endl; - Mat edges; - Canny(input, edges, 10, 100); - - return 0; - } - -Make sure your active solution configuration (:menuselection:`Build --> Configuration Manager`) is set to a debug build (usually called "Debug"). This should disable compiler optimizations so that viewing variables in the debugger can work reliably. - -Build your solution (:menuselection:`Build --> Build Solution`, or press *F7*). - -Before continuing, do not forget to add the command line argument of your input image to your project (:menuselection:`Right click on project --> Properties --> Configuration Properties --> Debugging` and then set the field ``Command Arguments`` with the location of the image). - -Now set a breakpoint on the source line that says - -.. code-block:: cpp - - Mat edges; - -To set the breakpoint, right-click on the source line and select :menuselection:`Breakpoints --> Insert Breakpoint` from the context menu. - -Launch the program in the debugger (:menuselection:`Debug --> Start Debugging`, or hit *F5*). When the breakpoint is hit, the program is paused and Visual Studio displays a yellow instruction pointer at the breakpoint: - -.. image:: images/breakpoint.png - -Now you can inspect the state of you program. For example, you can bring up the *Locals* window (:menuselection:`Debug --> Windows --> Locals`), which will show the names and values of the variables in the current scope: - -.. image:: images/vs_locals.png - -Note that the built-in *Locals* window will display text only. This is where the Image Watch plug-in comes in. Image Watch is like another *Locals* window, but with an image viewer built into it. To bring up Image Watch, select :menuselection:`View --> Other Windows --> Image Watch`. Like Visual Studio's *Locals* window, Image Watch can dock to the Visual Studio IDE. Also, Visual Studio will remember whether you had Image Watch open, and where it was located between debugging sessions. This means you only have to do this once--the next time you start debugging, Image Watch will be back where you left it. Here's what the docked Image Watch window looks like at our breakpoint: - -.. image:: images/toolwindow.jpg - :height: 320pt - -The radio button at the top left (*Locals/Watch*) selects what is shown in the *Image List* below: *Locals* lists all OpenCV image objects in the current scope (this list is automatically populated). *Watch* shows image expressions that have been pinned for continuous inspection (not described here, see `Image Watch documentation `_ for details). The image list shows basic information such as width, height, number of channels, and, if available, a thumbnail. In our example, the image list contains our two local image variables, *input* and *edges*. - -If an image has a thumbnail, left-clicking on that image will select it for detailed viewing in the *Image Viewer* on the right. The viewer lets you pan (drag mouse) and zoom (mouse wheel). It also displays the pixel coordinate and value at the current mouse position. - -.. image:: images/viewer.jpg - :height: 160pt - -Note that the second image in the list, *edges*, is shown as "invalid". This indicates that some data members of this image object have corrupt or invalid values (for example, a negative image width). This is expected at this point in the program, since the C++ constructor for *edges* has not run yet, and so its members have undefined values (in debug mode they are usually filled with "0xCD" bytes). - -From here you can single-step through your code (:menuselection:`Debug->Step Over`, or press *F10*) and watch the pixels change: if you step once, over the *Mat edges;* statement, the *edges* image will change from "invalid" to "empty", which means that it is now in a valid state (default constructed), even though it has not been initialized yet (using *cv::Mat::create()*, for example). If you make one more step over the *cv::Canny()* call, you will see a thumbnail of the edge image appear in the image list. - -Now assume you want to do a visual sanity check of the *cv::Canny()* implementation. Bring the *edges* image into the viewer by selecting it in the *Image List* and zoom into a region with a clearly defined edge: - -.. image:: images/edges_zoom.png - :height: 160pt - -Right-click on the *Image Viewer* to bring up the view context menu and enable :menuselection:`Link Views` (a check box next to the menu item indicates whether the option is enabled). - -.. image:: images/viewer_context_menu.png - :height: 120pt - -The :menuselection:`Link Views` feature keeps the view region fixed when flipping between images of the same size. To see how this works, select the input image from the image list--you should now see the corresponding zoomed-in region in the input image: - -.. image:: images/input_zoom.png - :height: 160pt - -You may also switch back and forth between viewing input and edges with your up/down cursor keys. That way you can easily verify that the detected edges line up nicely with the data in the input image. - -More ... -==================== - -Image watch has a number of more advanced features, such as - -#. pinning images to a *Watch* list for inspection across scopes or between debugging sessions - -#. clamping, thresholding, or diff'ing images directly inside the Watch window - -#. comparing an in-memory image against a reference image from a file - -Please refer to the online `Image Watch Documentation `_ for details--you also can get to the documentation page by clicking on the *Help* link in the Image Watch window: - -.. image:: images/help_button.jpg - :height: 80pt diff --git a/doc/tutorials/ios/hello/hello.rst b/doc/tutorials/ios/hello/hello.rst deleted file mode 100644 index 8435be54dc..0000000000 --- a/doc/tutorials/ios/hello/hello.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. _OpenCViOSHelloWorld: - -OpenCV iOS Hello -******************************* - -Goal -==== - -In this tutorial we will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Link OpenCV framework with Xcode - * How to write simple Hello World application using OpenCV and Xcode. - -*Linking OpenCV iOS* -====================== -Follow this step by step guide to link OpenCV to iOS. - -1. Create a new XCode project. - -2. Now we need to link *opencv2.framework* with Xcode. Select the project Navigator in the left hand panel and click on project name. - -3. Under the TARGETS click on Build Phases. Expand Link Binary With Libraries option. - -4. Click on Add others and go to directory where *opencv2.framework* is located and click open - -5. Now you can start writing your application. - -.. image:: images/linking_opencv_ios.png - :alt: OpenCV iOS in Xcode - :align: center - -*Hello OpenCV iOS Application* -=============================== - -Now we will learn how to write a simple Hello World Application in Xcode using OpenCV. - -.. container:: enumeratevisibleitemswithsquare - - * Link your project with OpenCV as shown in previous section. - * Open the file named *NameOfProject-Prefix.pch* ( replace NameOfProject with name of your project) and add the following lines of code. - -.. code-block:: cpp - - #ifdef __cplusplus - #import - #endif - -.. image:: images/header_directive.png - :alt: header - :align: center - -.. container:: enumeratevisibleitemswithsquare - - * Add the following lines of code to viewDidLoad method in ViewController.m. -.. code-block:: cpp - - UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Hello!" message:@"Welcome to OpenCV" delegate:self cancelButtonTitle:@"Continue" otherButtonTitles:nil]; - [alert show]; - -.. image:: images/view_did_load.png - :alt: view did load - :align: center - -.. container:: enumeratevisibleitemswithsquare - - * You are good to run the project. - -*Output* -========= - -.. image:: images/output.png - :alt: output - :align: center diff --git a/doc/tutorials/ios/image_manipulation/image_manipulation.rst b/doc/tutorials/ios/image_manipulation/image_manipulation.rst deleted file mode 100644 index 4bef75827f..0000000000 --- a/doc/tutorials/ios/image_manipulation/image_manipulation.rst +++ /dev/null @@ -1,129 +0,0 @@ -.. _OpenCViOSImageManipulation: - -OpenCV iOS - Image Processing -******************************* - -Goal -==== - -In this tutorial we will learn how to do basic image processing using OpenCV in iOS. - - -*Introduction* -============== - -In *OpenCV* all the image processing operations are usually carried out on the *Mat* structure. In iOS however, to render an image on screen it have to be an instance of the *UIImage* class. To convert an *OpenCV Mat* to an *UIImage* we use the *Core Graphics* framework available in iOS. Below is the code needed to covert back and forth between Mat's and UIImage's. - - -.. code-block:: cpp - - - (cv::Mat)cvMatFromUIImage:(UIImage *)image - { - CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage); - CGFloat cols = image.size.width; - CGFloat rows = image.size.height; - - cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels (color channels + alpha) - - CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to data - cols, // Width of bitmap - rows, // Height of bitmap - 8, // Bits per component - cvMat.step[0], // Bytes per row - colorSpace, // Colorspace - kCGImageAlphaNoneSkipLast | - kCGBitmapByteOrderDefault); // Bitmap info flags - - CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage); - CGContextRelease(contextRef); - - return cvMat; - } - -.. code-block:: cpp - - - (cv::Mat)cvMatGrayFromUIImage:(UIImage *)image - { - CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage); - CGFloat cols = image.size.width; - CGFloat rows = image.size.height; - - cv::Mat cvMat(rows, cols, CV_8UC1); // 8 bits per component, 1 channels - - CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to data - cols, // Width of bitmap - rows, // Height of bitmap - 8, // Bits per component - cvMat.step[0], // Bytes per row - colorSpace, // Colorspace - kCGImageAlphaNoneSkipLast | - kCGBitmapByteOrderDefault); // Bitmap info flags - - CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage); - CGContextRelease(contextRef); - - return cvMat; - } - -After the processing we need to convert it back to UIImage. The code below can handle both gray-scale and color image conversions (determined by the number of channels in the *if* statement). - -.. code-block:: cpp - - cv::Mat greyMat; - cv::cvtColor(inputMat, greyMat, COLOR_BGR2GRAY); - -After the processing we need to convert it back to UIImage. - -.. code-block:: cpp - - -(UIImage *)UIImageFromCVMat:(cv::Mat)cvMat - { - NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()]; - CGColorSpaceRef colorSpace; - - if (cvMat.elemSize() == 1) { - colorSpace = CGColorSpaceCreateDeviceGray(); - } else { - colorSpace = CGColorSpaceCreateDeviceRGB(); - } - - CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); - - // Creating CGImage from cv::Mat - CGImageRef imageRef = CGImageCreate(cvMat.cols, //width - cvMat.rows, //height - 8, //bits per component - 8 * cvMat.elemSize(), //bits per pixel - cvMat.step[0], //bytesPerRow - colorSpace, //colorspace - kCGImageAlphaNone|kCGBitmapByteOrderDefault,// bitmap info - provider, //CGDataProviderRef - NULL, //decode - false, //should interpolate - kCGRenderingIntentDefault //intent - ); - - - // Getting UIImage from CGImage - UIImage *finalImage = [UIImage imageWithCGImage:imageRef]; - CGImageRelease(imageRef); - CGDataProviderRelease(provider); - CGColorSpaceRelease(colorSpace); - - return finalImage; - } - -*Output* -================================== - -.. image:: images/output.jpg - :alt: header - :align: center - -Check out an instance of running code with more Image Effects on `YouTube `_ . - -.. raw:: html - -
- -
diff --git a/doc/tutorials/ios/table_of_content_ios/images/facedetect.jpg b/doc/tutorials/ios/images/facedetect.jpg similarity index 100% rename from doc/tutorials/ios/table_of_content_ios/images/facedetect.jpg rename to doc/tutorials/ios/images/facedetect.jpg diff --git a/doc/tutorials/ios/table_of_content_ios/images/image_effects.png b/doc/tutorials/ios/images/image_effects.png similarity index 100% rename from doc/tutorials/ios/table_of_content_ios/images/image_effects.png rename to doc/tutorials/ios/images/image_effects.png diff --git a/doc/tutorials/ios/table_of_content_ios/images/intro.png b/doc/tutorials/ios/images/intro.png similarity index 100% rename from doc/tutorials/ios/table_of_content_ios/images/intro.png rename to doc/tutorials/ios/images/intro.png diff --git a/doc/tutorials/ios/table_of_content_ios/table_of_content_ios.markdown b/doc/tutorials/ios/table_of_content_ios.markdown similarity index 100% rename from doc/tutorials/ios/table_of_content_ios/table_of_content_ios.markdown rename to doc/tutorials/ios/table_of_content_ios.markdown diff --git a/doc/tutorials/ios/table_of_content_ios/table_of_content_ios.rst b/doc/tutorials/ios/table_of_content_ios/table_of_content_ios.rst deleted file mode 100644 index 377446dee6..0000000000 --- a/doc/tutorials/ios/table_of_content_ios/table_of_content_ios.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. _Table-Of-Content-iOS: - -**OpenCV iOS** ------------------------------------------------------------ - -.. include:: ../../definitions/tocDefinitions.rst - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ =============================================================================== - |iOSOpenCV| **Title:** :ref:`OpenCViOSHelloWorld` - - *Compatibility:* > OpenCV 2.4.3 - - *Author:* Charu Hans - - You will learn how to link OpenCV with iOS and write a basic application. - - ============ =============================================================================== - - .. |iOSOpenCV| image:: images/intro.png - :height: 120pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ================ ============================================================================ - |iOSOpenCVImg| **Title:** :ref:`OpenCViOSImageManipulation` - - *Compatibility:* > OpenCV 2.4.3 - - *Author:* Charu Hans - - You will learn how to do simple image manipulation using OpenCV in iOS. - - ================ ============================================================================ - - .. |iOSOpenCVImg| image:: images/image_effects.png - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ================= ============================================================================ - |iOSOpenCVVideo| **Title:** :ref:`OpenCViOSVideoProcessing` - - *Compatibility:* > OpenCV 2.4.3 - - *Author:* Eduard Feicho - - You will learn how to capture and process video from camera using OpenCV in iOS. - - ================= ============================================================================ - - .. |iOSOpenCVVideo| image:: images/facedetect.jpg - :height: 120pt - :width: 90pt - - -.. raw:: latex - - \pagebreak - -.. toctree:: - :hidden: - - ../hello/hello - ../image_manipulation/image_manipulation - ../video_processing/video_processing diff --git a/doc/tutorials/ios/video_processing/video_processing.rst b/doc/tutorials/ios/video_processing/video_processing.rst deleted file mode 100644 index 9e6905be40..0000000000 --- a/doc/tutorials/ios/video_processing/video_processing.rst +++ /dev/null @@ -1,239 +0,0 @@ -.. _OpenCViOSVideoProcessing: - -OpenCV iOS - Video Processing -******************************* - -This tutorial explains how to process video frames using the iPhone's camera and OpenCV. - -Prerequisites: -================== - - * Xcode 4.3 or higher - * Basic knowledge of iOS programming (Objective-C, Interface Builder) - - -Including OpenCV library in your iOS project -================================================ - -The OpenCV library comes as a so-called framework, which you can directly drag-and-drop into your XCode project. Download the latest binary from . Alternatively follow this guide :ref:`iOS-Installation` to compile the framework manually. Once you have the framework, just drag-and-drop into XCode: - - .. image:: images/xcode_hello_ios_framework_drag_and_drop.png - - -Also you have to locate the prefix header that is used for all header files in the project. The file is typically located at "ProjectName/Supporting Files/ProjectName-Prefix.pch". There, you have add an include statement to import the opencv library. However, make sure you include opencv before you include UIKit and Foundation, because else you will get some weird compile errors that some macros like min and max are defined multiple times. For example the prefix header could look like the following: - -.. code-block:: objc - :linenos: - - // - // Prefix header for all source files of the 'VideoFilters' target in the 'VideoFilters' project - // - - #import - - #ifndef __IPHONE_4_0 - #warning "This project uses features only available in iOS SDK 4.0 and later." - #endif - - #ifdef __cplusplus - #import - #endif - - #ifdef __OBJC__ - #import - #import - #endif - - - -Example video frame processing project --------------------------------------- -User Interface -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -First, we create a simple iOS project, for example Single View Application. Then, we create and add an UIImageView and UIButton to start the camera and display the video frames. The storyboard could look like that: - - .. image:: images/xcode_hello_ios_viewcontroller_layout.png - - -Make sure to add and connect the IBOutlets and IBActions to the corresponding ViewController: - -.. code-block:: objc - :linenos: - - @interface ViewController : UIViewController - { - IBOutlet UIImageView* imageView; - IBOutlet UIButton* button; - } - - - (IBAction)actionStart:(id)sender; - - @end - - -Adding the Camera -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We add a camera controller to the view controller and initialize it when the view has loaded: - -.. code-block:: objc - :linenos: - - #import - using namespace cv; - - - @interface ViewController : UIViewController - { - ... - CvVideoCamera* videoCamera; - } - ... - @property (nonatomic, retain) CvVideoCamera* videoCamera; - - @end - -.. code-block:: objc - :linenos: - - - (void)viewDidLoad - { - [super viewDidLoad]; - // Do any additional setup after loading the view, typically from a nib. - - self.videoCamera = [[CvVideoCamera alloc] initWithParentView:imageView]; - self.videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionFront; - self.videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPreset352x288; - self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait; - self.videoCamera.defaultFPS = 30; - self.videoCamera.grayscale = NO; - } - -In this case, we initialize the camera and provide the imageView as a target for rendering each frame. CvVideoCamera is basically a wrapper around AVFoundation, so we provie as properties some of the AVFoundation camera options. For example we want to use the front camera, set the video size to 352x288 and a video orientation (the video camera normally outputs in landscape mode, which results in transposed data when you design a portrait application). - -The property defaultFPS sets the FPS of the camera. If the processing is less fast than the desired FPS, frames are automatically dropped. - -The property grayscale=YES results in a different colorspace, namely "YUV (YpCbCr 4:2:0)", while grayscale=NO will output 32 bit BGRA. - - -Additionally, we have to manually add framework dependencies of the opencv framework. Finally, you should have at least the following frameworks in your project: - - -* opencv2 - -* Accelerate - -* AssetsLibrary - -* AVFoundation - -* CoreGraphics - -* CoreImage - -* CoreMedia - -* CoreVideo - -* QuartzCore - -* UIKit - -* Foundation - - - .. image:: images/xcode_hello_ios_frameworks_add_dependencies.png - - -Processing frames -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We follow the delegation pattern, which is very common in iOS, to provide access to each camera frame. Basically, the View Controller has to implement the CvVideoCameraDelegate protocol and has to be set as delegate to the video camera: - -.. code-block:: objc - :linenos: - - @interface ViewController : UIViewController - - - -.. code-block:: objc - :linenos: - - - (void)viewDidLoad - { - ... - self.videoCamera = [[CvVideoCamera alloc] initWithParentView:imageView]; - self.videoCamera.delegate = self; - ... - } - - -.. code-block:: objc - :linenos: - - #pragma mark - Protocol CvVideoCameraDelegate - - #ifdef __cplusplus - - (void)processImage:(Mat&)image; - { - // Do some OpenCV stuff with the image - } - #endif - -Note that we are using C++ here (cv::Mat). -Important: You have to rename the view controller's extension .m into .mm, so that the compiler compiles it under the assumption of Objective-C++ (Objective-C and C++ mixed). Then, __cplusplus is defined when the compiler is processing the file for C++ code. Therefore, we put our code within a block where __cplusplus is defined. - - -Basic video processing -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -From here you can start processing video frames. For example the following snippet color-inverts the image: - - -.. code-block:: objc - :linenos: - - - (void)processImage:(Mat&)image; - { - // Do some OpenCV stuff with the image - Mat image_copy; - cvtColor(image, image_copy, COLOR_BGR2GRAY); - - // invert image - bitwise_not(image_copy, image_copy); - - //Convert BGR to BGRA (three channel to four channel) - Mat bgr; - cvtColor(image_copy, bgr, COLOR_GRAY2BGR); - - cvtColor(bgr, image, COLOR_BGR2BGRA); - } - - -Start! -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Finally, we have to tell the camera to actually start/stop working. The following code will start the camera when you press the button, assuming you connected the UI properly: - -.. code-block:: objc - :linenos: - - #pragma mark - UI Actions - - - (IBAction)actionStart:(id)sender; - { - [self.videoCamera start]; - } - - - -Hints -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Try to avoid costly matrix copy operations as much as you can, especially if you are aiming for real-time. As the image data is passed as reference, work in-place, if possible. - -When you are working on grayscale data, turn set grayscale = YES as the YUV colorspace gives you directly access the luminance plane. - -The Accelerate framework provides some CPU-accelerated DSP filters, which come handy in your case. diff --git a/doc/tutorials/ml/table_of_content_ml/images/introduction_to_svm.png b/doc/tutorials/ml/images/introduction_to_svm.png similarity index 100% rename from doc/tutorials/ml/table_of_content_ml/images/introduction_to_svm.png rename to doc/tutorials/ml/images/introduction_to_svm.png diff --git a/doc/tutorials/ml/table_of_content_ml/images/non_linear_svms.png b/doc/tutorials/ml/images/non_linear_svms.png similarity index 100% rename from doc/tutorials/ml/table_of_content_ml/images/non_linear_svms.png rename to doc/tutorials/ml/images/non_linear_svms.png diff --git a/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.rst b/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.rst deleted file mode 100644 index 01abd9e553..0000000000 --- a/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.rst +++ /dev/null @@ -1,187 +0,0 @@ -.. _introductiontosvms: - -Introduction to Support Vector Machines -*************************************** - -Goal -==== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - + Use the OpenCV functions :svms:`CvSVM::train ` to build a classifier based on SVMs and :svms:`CvSVM::predict ` to test its performance. - -What is a SVM? -============== - -A Support Vector Machine (SVM) is a discriminative classifier formally defined by a separating hyperplane. In other words, given labeled training data (*supervised learning*), the algorithm outputs an optimal hyperplane which categorizes new examples. - -In which sense is the hyperplane obtained optimal? Let's consider the following -simple problem: - - For a linearly separable set of 2D-points which belong to one of two classes, find a separating straight line. - -.. image:: images/separating-lines.png - :alt: A seperation example - :align: center - -.. note:: In this example we deal with lines and points in the Cartesian plane instead of hyperplanes and vectors in a high dimensional space. This is a simplification of the problem.It is important to understand that this is done only because our intuition is better built from examples that are easy to imagine. However, the same concepts apply to tasks where the examples to classify lie in a space whose dimension is higher than two. - -In the above picture you can see that there exists multiple lines that offer a solution to the problem. Is any of them better than the others? We can intuitively define a criterion to estimate the worth of the lines: - - A line is bad if it passes too close to the points because it will be noise sensitive and it will not generalize correctly. Therefore, our goal should be to find the line passing as far as possible from all points. - -Then, the operation of the SVM algorithm is based on finding the hyperplane that gives the largest minimum distance to the training examples. Twice, this distance receives the important name of **margin** within SVM's theory. Therefore, the optimal separating hyperplane *maximizes* the margin of the training data. - -.. image:: images/optimal-hyperplane.png - :alt: The Optimal hyperplane - :align: center - -How is the optimal hyperplane computed? -======================================= - -Let's introduce the notation used to define formally a hyperplane: - -.. math:: - f(x) = \beta_{0} + \beta^{T} x, - -where :math:`\beta` is known as the *weight vector* and :math:`\beta_{0}` as the *bias*. - -.. seealso:: A more in depth description of this and hyperplanes you can find in the section 4.5 (*Seperating Hyperplanes*) of the book: *Elements of Statistical Learning* by T. Hastie, R. Tibshirani and J. H. Friedman. - -The optimal hyperplane can be represented in an infinite number of different ways by scaling of :math:`\beta` and :math:`\beta_{0}`. As a matter of convention, among all the possible representations of the hyperplane, the one chosen is - -.. math:: - |\beta_{0} + \beta^{T} x| = 1 - -where :math:`x` symbolizes the training examples closest to the hyperplane. In general, the training examples that are closest to the hyperplane are called **support vectors**. This representation is known as the **canonical hyperplane**. - -Now, we use the result of geometry that gives the distance between a point :math:`x` and a hyperplane :math:`(\beta, \beta_{0})`: - -.. math:: - \mathrm{distance} = \frac{|\beta_{0} + \beta^{T} x|}{||\beta||}. - -In particular, for the canonical hyperplane, the numerator is equal to one and the distance to the support vectors is - -.. math:: - \mathrm{distance}_{\text{ support vectors}} = \frac{|\beta_{0} + \beta^{T} x|}{||\beta||} = \frac{1}{||\beta||}. - -Recall that the margin introduced in the previous section, here denoted as :math:`M`, is twice the distance to the closest examples: - -.. math:: - M = \frac{2}{||\beta||} - -Finally, the problem of maximizing :math:`M` is equivalent to the problem of minimizing a function :math:`L(\beta)` subject to some constraints. The constraints model the requirement for the hyperplane to classify correctly all the training examples :math:`x_{i}`. Formally, - -.. math:: - \min_{\beta, \beta_{0}} L(\beta) = \frac{1}{2}||\beta||^{2} \text{ subject to } y_{i}(\beta^{T} x_{i} + \beta_{0}) \geq 1 \text{ } \forall i, - -where :math:`y_{i}` represents each of the labels of the training examples. - -This is a problem of Lagrangian optimization that can be solved using Lagrange multipliers to obtain the weight vector :math:`\beta` and the bias :math:`\beta_{0}` of the optimal hyperplane. - -Source Code -=========== - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/ml/introduction_to_svm/introduction_to_svm.cpp - :language: cpp - :linenos: - :tab-width: 4 - -Explanation -=========== - -1. **Set up the training data** - - The training data of this exercise is formed by a set of labeled 2D-points that belong to one of two different classes; one of the classes consists of one point and the other of three points. - - .. code-block:: cpp - - float labels[4] = {1.0, -1.0, -1.0, -1.0}; - float trainingData[4][2] = {{501, 10}, {255, 10}, {501, 255}, {10, 501}}; - - The function :svms:`CvSVM::train ` that will be used afterwards requires the training data to be stored as :basicstructures:`Mat ` objects of floats. Therefore, we create these objects from the arrays defined above: - - .. code-block:: cpp - - Mat trainingDataMat(4, 2, CV_32FC1, trainingData); - Mat labelsMat (4, 1, CV_32FC1, labels); - -2. **Set up SVM's parameters** - - In this tutorial we have introduced the theory of SVMs in the most simple case, when the training examples are spread into two classes that are linearly separable. However, SVMs can be used in a wide variety of problems (e.g. problems with non-linearly separable data, a SVM using a kernel function to raise the dimensionality of the examples, etc). As a consequence of this, we have to define some parameters before training the SVM. These parameters are stored in an object of the class :svms:`CvSVMParams ` . - - .. code-block:: cpp - - ml::SVM::Params params; - params.svmType = ml::SVM::C_SVC; - params.kernelType = ml::SVM::LINEAR; - params.termCrit = TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6); - - * *Type of SVM*. We choose here the type **ml::SVM::C_SVC** that can be used for n-class classification (n :math:`\geq` 2). This parameter is defined in the attribute *ml::SVM::Params.svmType*. - - .. note:: The important feature of the type of SVM **CvSVM::C_SVC** deals with imperfect separation of classes (i.e. when the training data is non-linearly separable). This feature is not important here since the data is linearly separable and we chose this SVM type only for being the most commonly used. - - * *Type of SVM kernel*. We have not talked about kernel functions since they are not interesting for the training data we are dealing with. Nevertheless, let's explain briefly now the main idea behind a kernel function. It is a mapping done to the training data to improve its resemblance to a linearly separable set of data. This mapping consists of increasing the dimensionality of the data and is done efficiently using a kernel function. We choose here the type **ml::SVM::LINEAR** which means that no mapping is done. This parameter is defined in the attribute *ml::SVMParams.kernel_type*. - - * *Termination criteria of the algorithm*. The SVM training procedure is implemented solving a constrained quadratic optimization problem in an **iterative** fashion. Here we specify a maximum number of iterations and a tolerance error so we allow the algorithm to finish in less number of steps even if the optimal hyperplane has not been computed yet. This parameter is defined in a structure :oldbasicstructures:`cvTermCriteria `. - -3. **Train the SVM** - - We call the method `CvSVM::train `_ to build the SVM model. - - .. code-block:: cpp - - CvSVM SVM; - SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params); - -4. **Regions classified by the SVM** - - The method :svms:`CvSVM::predict ` is used to classify an input sample using a trained SVM. In this example we have used this method in order to color the space depending on the prediction done by the SVM. In other words, an image is traversed interpreting its pixels as points of the Cartesian plane. Each of the points is colored depending on the class predicted by the SVM; in green if it is the class with label 1 and in blue if it is the class with label -1. - - .. code-block:: cpp - - Vec3b green(0,255,0), blue (255,0,0); - - for (int i = 0; i < image.rows; ++i) - for (int j = 0; j < image.cols; ++j) - { - Mat sampleMat = (Mat_(1,2) << i,j); - float response = SVM.predict(sampleMat); - - if (response == 1) - image.at(j, i) = green; - else - if (response == -1) - image.at(j, i) = blue; - } - -5. **Support vectors** - - We use here a couple of methods to obtain information about the support vectors. The method :svms:`CvSVM::get_support_vector_count ` outputs the total number of support vectors used in the problem and with the method :svms:`CvSVM::get_support_vector ` we obtain each of the support vectors using an index. We have used this methods here to find the training examples that are support vectors and highlight them. - - .. code-block:: cpp - - int c = SVM.get_support_vector_count(); - - for (int i = 0; i < c; ++i) - { - const float* v = SVM.get_support_vector(i); // get and then highlight with grayscale - circle( image, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thickness, lineType); - } - -Results -======= - -.. container:: enumeratevisibleitemswithsquare - - * The code opens an image and shows the training examples of both classes. The points of one class are represented with white circles and black ones are used for the other class. - - * The SVM is trained and used to classify all the pixels of the image. This results in a division of the image in a blue region and a green region. The boundary between both regions is the optimal separating hyperplane. - - * Finally the support vectors are shown using gray rings around the training examples. - -.. image:: images/svm_intro_result.png - :alt: The seperated planes - :align: center diff --git a/doc/tutorials/ml/non_linear_svms/non_linear_svms.markdown b/doc/tutorials/ml/non_linear_svms/non_linear_svms.markdown index 48139c04e1..5c36e425b3 100644 --- a/doc/tutorials/ml/non_linear_svms/non_linear_svms.markdown +++ b/doc/tutorials/ml/non_linear_svms/non_linear_svms.markdown @@ -91,7 +91,7 @@ Source Code You may also find the source code and these video file in the `samples/cpp/tutorial_code/gpu/non_linear_svms/non_linear_svms` folder of the OpenCV source library -or [download it from here ](samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp). +or [download it from here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp). @includelineno cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp diff --git a/doc/tutorials/ml/non_linear_svms/non_linear_svms.rst b/doc/tutorials/ml/non_linear_svms/non_linear_svms.rst deleted file mode 100644 index f39c817e4f..0000000000 --- a/doc/tutorials/ml/non_linear_svms/non_linear_svms.rst +++ /dev/null @@ -1,232 +0,0 @@ -.. _nonLinearSvmS: - -Support Vector Machines for Non-Linearly Separable Data -******************************************************* - -Goal -==== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - + Define the optimization problem for SVMs when it is not possible to separate linearly the training data. - - + How to configure the parameters in :svms:`CvSVMParams ` to adapt your SVM for this class of problems. - -Motivation -========== - -Why is it interesting to extend the SVM optimation problem in order to handle non-linearly separable training data? Most of the applications in which SVMs are used in computer vision require a more powerful tool than a simple linear classifier. This stems from the fact that in these tasks **the training data can be rarely separated using an hyperplane**. - -Consider one of these tasks, for example, face detection. The training data in this case is composed by a set of images that are faces and another set of images that are non-faces (*every other thing in the world except from faces*). This training data is too complex so as to find a representation of each sample (*feature vector*) that could make the whole set of faces linearly separable from the whole set of non-faces. - -Extension of the Optimization Problem -===================================== - -Remember that using SVMs we obtain a separating hyperplane. Therefore, since the training data is now non-linearly separable, we must admit that the hyperplane found will misclassify some of the samples. This *misclassification* is a new variable in the optimization that must be taken into account. The new model has to include both the old requirement of finding the hyperplane that gives the biggest margin and the new one of generalizing the training data correctly by not allowing too many classification errors. - -We start here from the formulation of the optimization problem of finding the hyperplane which maximizes the **margin** (this is explained in the :ref:`previous tutorial `): - -.. math:: - \min_{\beta, \beta_{0}} L(\beta) = \frac{1}{2}||\beta||^{2} \text{ subject to } y_{i}(\beta^{T} x_{i} + \beta_{0}) \geq 1 \text{ } \forall i - -There are multiple ways in which this model can be modified so it takes into account the misclassification errors. For example, one could think of minimizing the same quantity plus a constant times the number of misclassification errors in the training data, i.e.: - -.. math:: - \min ||\beta||^{2} + C \text{(\# misclassication errors)} - -However, this one is not a very good solution since, among some other reasons, we do not distinguish between samples that are misclassified with a small distance to their appropriate decision region or samples that are not. Therefore, a better solution will take into account the *distance of the misclassified samples to their correct decision regions*, i.e.: - -.. math:: - \min ||\beta||^{2} + C \text{(distance of misclassified samples to their correct regions)} - -For each sample of the training data a new parameter :math:`\xi_{i}` is defined. Each one of these parameters contains the distance from its corresponding training sample to their correct decision region. The following picture shows non-linearly separable training data from two classes, a separating hyperplane and the distances to their correct regions of the samples that are misclassified. - -.. image:: images/sample-errors-dist.png - :alt: Samples misclassified and their distances to their correct regions - :align: center - -.. note:: Only the distances of the samples that are misclassified are shown in the picture. The distances of the rest of the samples are zero since they lay already in their correct decision region. - -The red and blue lines that appear on the picture are the margins to each one of the decision regions. It is very **important** to realize that each of the :math:`\xi_{i}` goes from a misclassified training sample to the margin of its appropriate region. - -Finally, the new formulation for the optimization problem is: - -.. math:: - \min_{\beta, \beta_{0}} L(\beta) = ||\beta||^{2} + C \sum_{i} {\xi_{i}} \text{ subject to } y_{i}(\beta^{T} x_{i} + \beta_{0}) \geq 1 - \xi_{i} \text{ and } \xi_{i} \geq 0 \text{ } \forall i - -How should the parameter C be chosen? It is obvious that the answer to this question depends on how the training data is distributed. Although there is no general answer, it is useful to take into account these rules: - -.. container:: enumeratevisibleitemswithsquare - - * Large values of C give solutions with *less misclassification errors* but a *smaller margin*. Consider that in this case it is expensive to make misclassification errors. Since the aim of the optimization is to minimize the argument, few misclassifications errors are allowed. - - * Small values of C give solutions with *bigger margin* and *more classification errors*. In this case the minimization does not consider that much the term of the sum so it focuses more on finding a hyperplane with big margin. - -Source Code -=========== - -You may also find the source code and these video file in the :file:`samples/cpp/tutorial_code/gpu/non_linear_svms/non_linear_svms` folder of the OpenCV source library or :download:`download it from here <../../../../samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp>`. - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp - :language: cpp - :linenos: - :tab-width: 4 - :lines: 1-12, 23-24, 27- - -Explanation -=========== - -1. **Set up the training data** - - The training data of this exercise is formed by a set of labeled 2D-points that belong to one of two different classes. To make the exercise more appealing, the training data is generated randomly using a uniform probability density functions (PDFs). - - We have divided the generation of the training data into two main parts. - - In the first part we generate data for both classes that is linearly separable. - - .. code-block:: cpp - - // Generate random points for the class 1 - Mat trainClass = trainData.rowRange(0, nLinearSamples); - // The x coordinate of the points is in [0, 0.4) - Mat c = trainClass.colRange(0, 1); - rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(0.4 * WIDTH)); - // The y coordinate of the points is in [0, 1) - c = trainClass.colRange(1,2); - rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); - - // Generate random points for the class 2 - trainClass = trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES); - // The x coordinate of the points is in [0.6, 1] - c = trainClass.colRange(0 , 1); - rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH)); - // The y coordinate of the points is in [0, 1) - c = trainClass.colRange(1,2); - rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); - - In the second part we create data for both classes that is non-linearly separable, data that overlaps. - - .. code-block:: cpp - - // Generate random points for the classes 1 and 2 - trainClass = trainData.rowRange( nLinearSamples, 2*NTRAINING_SAMPLES-nLinearSamples); - // The x coordinate of the points is in [0.4, 0.6) - c = trainClass.colRange(0,1); - rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH)); - // The y coordinate of the points is in [0, 1) - c = trainClass.colRange(1,2); - rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); - -2. **Set up SVM's parameters** - - .. seealso:: - - In the previous tutorial :ref:`introductiontosvms` there is an explanation of the atributes of the class :svms:`CvSVMParams ` that we configure here before training the SVM. - - .. code-block:: cpp - - CvSVMParams params; - params.svm_type = SVM::C_SVC; - params.C = 0.1; - params.kernel_type = SVM::LINEAR; - params.term_crit = TermCriteria(TermCriteria::ITER, (int)1e7, 1e-6); - - There are just two differences between the configuration we do here and the one that was done in the :ref:`previous tutorial ` that we use as reference. - - * *CvSVM::C_SVC*. We chose here a small value of this parameter in order not to punish too much the misclassification errors in the optimization. The idea of doing this stems from the will of obtaining a solution close to the one intuitively expected. However, we recommend to get a better insight of the problem by making adjustments to this parameter. - - .. note:: Here there are just very few points in the overlapping region between classes, giving a smaller value to **FRAC_LINEAR_SEP** the density of points can be incremented and the impact of the parameter **CvSVM::C_SVC** explored deeply. - - * *Termination Criteria of the algorithm*. The maximum number of iterations has to be increased considerably in order to solve correctly a problem with non-linearly separable training data. In particular, we have increased in five orders of magnitude this value. - -3. **Train the SVM** - - We call the method :svms:`CvSVM::train ` to build the SVM model. Watch out that the training process may take a quite long time. Have patiance when your run the program. - - .. code-block:: cpp - - CvSVM svm; - svm.train(trainData, labels, Mat(), Mat(), params); - -4. **Show the Decision Regions** - - The method :svms:`CvSVM::predict ` is used to classify an input sample using a trained SVM. In this example we have used this method in order to color the space depending on the prediction done by the SVM. In other words, an image is traversed interpreting its pixels as points of the Cartesian plane. Each of the points is colored depending on the class predicted by the SVM; in dark green if it is the class with label 1 and in dark blue if it is the class with label 2. - - .. code-block:: cpp - - Vec3b green(0,100,0), blue (100,0,0); - for (int i = 0; i < I.rows; ++i) - for (int j = 0; j < I.cols; ++j) - { - Mat sampleMat = (Mat_(1,2) << i, j); - float response = svm.predict(sampleMat); - - if (response == 1) I.at(j, i) = green; - else if (response == 2) I.at(j, i) = blue; - } - -5. **Show the training data** - - The method :drawingFunc:`circle ` is used to show the samples that compose the training data. The samples of the class labeled with 1 are shown in light green and in light blue the samples of the class labeled with 2. - - .. code-block:: cpp - - int thick = -1; - int lineType = 8; - float px, py; - // Class 1 - for (int i = 0; i < NTRAINING_SAMPLES; ++i) - { - px = trainData.at(i,0); - py = trainData.at(i,1); - circle(I, Point( (int) px, (int) py ), 3, Scalar(0, 255, 0), thick, lineType); - } - // Class 2 - for (int i = NTRAINING_SAMPLES; i <2*NTRAINING_SAMPLES; ++i) - { - px = trainData.at(i,0); - py = trainData.at(i,1); - circle(I, Point( (int) px, (int) py ), 3, Scalar(255, 0, 0), thick, lineType); - } - -6. **Support vectors** - - We use here a couple of methods to obtain information about the support vectors. The method :svms:`CvSVM::get_support_vector_count ` outputs the total number of support vectors used in the problem and with the method :svms:`CvSVM::get_support_vector ` we obtain each of the support vectors using an index. We have used this methods here to find the training examples that are support vectors and highlight them. - - .. code-block:: cpp - - thick = 2; - lineType = 8; - int x = svm.get_support_vector_count(); - - for (int i = 0; i < x; ++i) - { - const float* v = svm.get_support_vector(i); - circle( I, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thick, lineType); - } - -Results -======== - -.. container:: enumeratevisibleitemswithsquare - - * The code opens an image and shows the training examples of both classes. The points of one class are represented with light green and light blue ones are used for the other class. - - * The SVM is trained and used to classify all the pixels of the image. This results in a division of the image in a blue region and a green region. The boundary between both regions is the separating hyperplane. Since the training data is non-linearly separable, it can be seen that some of the examples of both classes are misclassified; some green points lay on the blue region and some blue points lay on the green one. - - * Finally the support vectors are shown using gray rings around the training examples. - -.. image:: images/svm_non_linear_result.png - :alt: Training data and decision regions given by the SVM - :width: 300pt - :align: center - -You may observe a runtime instance of this on the `YouTube here `_. - -.. raw:: html - -
- -
diff --git a/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.markdown b/doc/tutorials/ml/table_of_content_ml.markdown similarity index 100% rename from doc/tutorials/ml/table_of_content_ml/table_of_content_ml.markdown rename to doc/tutorials/ml/table_of_content_ml.markdown diff --git a/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.rst b/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.rst deleted file mode 100644 index 4691756a96..0000000000 --- a/doc/tutorials/ml/table_of_content_ml/table_of_content_ml.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. _Table-Of-Content-Ml: - -*ml* module. Machine Learning ------------------------------------------------------------ - -Use the powerfull machine learning classes for statistical classification, regression and clustering of data. - -.. include:: ../../definitions/tocDefinitions.rst - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ ============================================== - |IntroSVM| **Title:** :ref:`introductiontosvms` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_FernandoI| - - Learn what a Suport Vector Machine is. - - ============ ============================================== - - .. |IntroSVM| image:: images/introduction_to_svm.png - :height: 90pt - :width: 90pt - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ ============================================== - |NonLinSVM| **Title:** :ref:`nonLinearSvmS` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_FernandoI| - - Here you will learn how to define the optimization problem for SVMs when it is not possible to separate linearly the training data. - - ============ ============================================== - - .. |NonLinSVM| image:: images/non_linear_svms.png - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. toctree:: - :hidden: - - ../introduction_to_svm/introduction_to_svm - ../non_linear_svms/non_linear_svms diff --git a/doc/tutorials/objdetect/cascade_classifier/cascade_classifier.rst b/doc/tutorials/objdetect/cascade_classifier/cascade_classifier.rst deleted file mode 100644 index 7529157033..0000000000 --- a/doc/tutorials/objdetect/cascade_classifier/cascade_classifier.rst +++ /dev/null @@ -1,132 +0,0 @@ -.. _cascade_classifier: - -Cascade Classifier -******************* - -Goal -===== - -In this tutorial you will learn how to: - -.. container:: enumeratevisibleitemswithsquare - - * Use the :cascade_classifier:`CascadeClassifier <>` class to detect objects in a video stream. Particularly, we will use the functions: - - * :cascade_classifier_load:`load <>` to load a .xml classifier file. It can be either a Haar or a LBP classifer - * :cascade_classifier_detect_multiscale:`detectMultiScale <>` to perform the detection. - - -Theory -====== - -Code -==== - -This tutorial code's is shown lines below. You can also download it from `here `_ . The second version (using LBP for face detection) can be `found here `_ - -.. code-block:: cpp - - #include "opencv2/objdetect.hpp" - #include "opencv2/highgui.hpp" - #include "opencv2/imgproc.hpp" - - #include - #include - - using namespace std; - using namespace cv; - - /* Function Headers */ - void detectAndDisplay( Mat frame ); - - /* Global variables */ - String face_cascade_name = "haarcascade_frontalface_alt.xml"; - String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml"; - CascadeClassifier face_cascade; - CascadeClassifier eyes_cascade; - String window_name = "Capture - Face detection"; - - /* @function main */ - int main( void ) - { - VideoCapture capture; - Mat frame; - - //-- 1. Load the cascades - if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading face cascade\n"); return -1; }; - if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading eyes cascade\n"); return -1; }; - - //-- 2. Read the video stream - capture.open( -1 ); - if ( ! capture.isOpened() ) { printf("--(!)Error opening video capture\n"); return -1; } - - while ( capture.read(frame) ) - { - if( frame.empty() ) - { - printf(" --(!) No captured frame -- Break!"); - break; - } - - //-- 3. Apply the classifier to the frame - detectAndDisplay( frame ); - - int c = waitKey(10); - if( (char)c == 27 ) { break; } // escape - } - return 0; - } - - /* @function detectAndDisplay */ - void detectAndDisplay( Mat frame ) - { - std::vector faces; - Mat frame_gray; - - cvtColor( frame, frame_gray, COLOR_BGR2GRAY ); - equalizeHist( frame_gray, frame_gray ); - - //-- Detect faces - face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CASCADE_SCALE_IMAGE, Size(30, 30) ); - - for( size_t i = 0; i < faces.size(); i++ ) - { - Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 ); - ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 ); - - Mat faceROI = frame_gray( faces[i] ); - std::vector eyes; - - //-- In each face, detect eyes - eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CASCADE_SCALE_IMAGE, Size(30, 30) ); - - for( size_t j = 0; j < eyes.size(); j++ ) - { - Point eye_center( faces[i].x + eyes[j].x + eyes[j].width/2, faces[i].y + eyes[j].y + eyes[j].height/2 ); - int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 ); - circle( frame, eye_center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 ); - } - } - //-- Show what you got - imshow( window_name, frame ); - } - -Explanation -============ - -Result -====== - -#. Here is the result of running the code above and using as input the video stream of a build-in webcam: - - .. image:: images/Cascade_Classifier_Tutorial_Result_Haar.jpg - :align: center - :height: 300pt - - Remember to copy the files *haarcascade_frontalface_alt.xml* and *haarcascade_eye_tree_eyeglasses.xml* in your current directory. They are located in *opencv/data/haarcascades* - -#. This is the result of using the file *lbpcascade_frontalface.xml* (LBP trained) for the face detection. For the eyes we keep using the file used in the tutorial. - - .. image:: images/Cascade_Classifier_Tutorial_Result_LBP.jpg - :align: center - :height: 300pt diff --git a/doc/tutorials/objdetect/table_of_content_objdetect/images/Cascade_Classifier_Tutorial_Cover.jpg b/doc/tutorials/objdetect/images/Cascade_Classifier_Tutorial_Cover.jpg similarity index 100% rename from doc/tutorials/objdetect/table_of_content_objdetect/images/Cascade_Classifier_Tutorial_Cover.jpg rename to doc/tutorials/objdetect/images/Cascade_Classifier_Tutorial_Cover.jpg diff --git a/doc/tutorials/objdetect/table_of_content_objdetect/table_of_content_objdetect.markdown b/doc/tutorials/objdetect/table_of_content_objdetect.markdown similarity index 100% rename from doc/tutorials/objdetect/table_of_content_objdetect/table_of_content_objdetect.markdown rename to doc/tutorials/objdetect/table_of_content_objdetect.markdown diff --git a/doc/tutorials/objdetect/table_of_content_objdetect/table_of_content_objdetect.rst b/doc/tutorials/objdetect/table_of_content_objdetect/table_of_content_objdetect.rst deleted file mode 100644 index c9df3eb1dc..0000000000 --- a/doc/tutorials/objdetect/table_of_content_objdetect/table_of_content_objdetect.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _Table-Of-Content-ObjDetect: - -*objdetect* module. Object Detection ------------------------------------------------------------ - -Ever wondered how your digital camera detects peoples and faces? Look here to find out! - -.. include:: ../../definitions/tocDefinitions.rst - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ===================== ============================================== - |CascadeClassif| **Title:** :ref:`cascade_classifier` - - *Compatibility:* > OpenCV 2.0 - - *Author:* |Author_AnaH| - - Here we learn how to use *objdetect* to find objects in our images or videos - - ===================== ============================================== - - .. |CascadeClassif| image:: images/Cascade_Classifier_Tutorial_Cover.jpg - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. toctree:: - :hidden: - - ../cascade_classifier/cascade_classifier diff --git a/doc/tutorials/photo/hdr_imaging/hdr_imaging.rst b/doc/tutorials/photo/hdr_imaging/hdr_imaging.rst deleted file mode 100644 index 40a23edad3..0000000000 --- a/doc/tutorials/photo/hdr_imaging/hdr_imaging.rst +++ /dev/null @@ -1,122 +0,0 @@ -.. _hdrimaging: - -High Dynamic Range Imaging -*************************************** - -Introduction ------------------- -Today most digital images and imaging devices use 8 bits per channel thus limiting the dynamic range of the device to two orders of magnitude (actually 256 levels), while human eye can adapt to lighting conditions varying by ten orders of magnitude. When we take photographs of a real world scene bright regions may be overexposed, while the dark ones may be underexposed, so we can’t capture all details using a single exposure. HDR imaging works with images that use more that 8 bits per channel (usually 32-bit float values), allowing much wider dynamic range. - -There are different ways to obtain HDR images, but the most common one is to use photographs of the scene taken with different exposure values. To combine this exposures it is useful to know your camera’s response function and there are algorithms to estimate it. After the HDR image has been blended it has to be converted back to 8-bit to view it on usual displays. This process is called tonemapping. Additional complexities arise when objects of the scene or camera move between shots, since images with different exposures should be registered and aligned. - -In this tutorial we show how to generate and display HDR image from an exposure sequence. In our case images are already aligned and there are no moving objects. We also demonstrate an alternative approach called exposure fusion that produces low dynamic range image. Each step of HDR pipeline can be implemented using different algorithms so take a look at the reference manual to see them all. - -Exposure sequence ------------------- - -.. image:: images/memorial.png - :height: 357pt - :width: 242pt - :alt: Exposure sequence - :align: center - -Source Code -=========== - -.. literalinclude:: ../../../../samples/cpp/tutorial_code/photo/hdr_imaging/hdr_imaging.cpp - :language: cpp - :linenos: - :tab-width: 4 - -Explanation -=========== - -1. **Load images and exposure times** - - .. code-block:: cpp - - vector images; - vector times; - loadExposureSeq(argv[1], images, times); - - Firstly we load input images and exposure times from user-defined folder. The folder should contain images and *list.txt* - file that contains file names and inverse exposure times. - - For our image sequence the list is following: - - .. code-block:: none - - memorial00.png 0.03125 - memorial01.png 0.0625 - ... - memorial15.png 1024 - -2. **Estimate camera response** - - .. code-block:: cpp - - Mat response; - Ptr calibrate = createCalibrateDebevec(); - calibrate->process(images, response, times); - - It is necessary to know camera response function (CRF) for a lot of HDR construction algorithms. We use one of the calibration algorithms to estimate inverse CRF for all 256 pixel values. - -3. **Make HDR image** - - .. code-block:: cpp - - Mat hdr; - Ptr merge_debevec = createMergeDebevec(); - merge_debevec->process(images, hdr, times, response); - - We use Debevec's weighting scheme to construct HDR image using response calculated in the previous item. - -4. **Tonemap HDR image** - - .. code-block:: cpp - - Mat ldr; - Ptr tonemap = createTonemapDurand(2.2f); - tonemap->process(hdr, ldr); - - Since we want to see our results on common LDR display we have to map our HDR image to 8-bit range preserving most details. It is the main goal of tonemapping methods. We use tonemapper with bilateral filtering and set 2.2 as the value for gamma correction. - -5. **Perform exposure fusion** - - .. code-block:: cpp - - Mat fusion; - Ptr merge_mertens = createMergeMertens(); - merge_mertens->process(images, fusion); - - There is an alternative way to merge our exposures in case when we don't need HDR image. This process is called exposure fusion and produces LDR image that doesn't require gamma correction. It also doesn't use exposure values of the photographs. - -6. **Write results** - - .. code-block:: cpp - - imwrite("fusion.png", fusion * 255); - imwrite("ldr.png", ldr * 255); - imwrite("hdr.hdr", hdr); - - Now it's time to look at the results. Note that HDR image can't be stored in one of common image formats, so we save it to Radiance image (.hdr). Also all HDR imaging functions return results in [0, 1] range so we should multiply result by 255. - -Results -======= - -Tonemapped image ------------------- - -.. image:: images/ldr.png - :height: 357pt - :width: 242pt - :alt: Tonemapped image - :align: center - -Exposure fusion ------------------- - -.. image:: images/fusion.png - :height: 357pt - :width: 242pt - :alt: Exposure fusion - :align: center diff --git a/doc/tutorials/photo/table_of_content_photo/images/hdr.png b/doc/tutorials/photo/images/hdr.png similarity index 100% rename from doc/tutorials/photo/table_of_content_photo/images/hdr.png rename to doc/tutorials/photo/images/hdr.png diff --git a/doc/tutorials/photo/table_of_content_photo/table_of_content_photo.markdown b/doc/tutorials/photo/table_of_content_photo.markdown similarity index 100% rename from doc/tutorials/photo/table_of_content_photo/table_of_content_photo.markdown rename to doc/tutorials/photo/table_of_content_photo.markdown diff --git a/doc/tutorials/photo/table_of_content_photo/table_of_content_photo.rst b/doc/tutorials/photo/table_of_content_photo/table_of_content_photo.rst deleted file mode 100644 index bacb1dba07..0000000000 --- a/doc/tutorials/photo/table_of_content_photo/table_of_content_photo.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _Table-Of-Content-Photo: - -*photo* module. Computational photography ------------------------------------------------------------ - -Use OpenCV for advanced photo processing. - -.. include:: ../../definitions/tocDefinitions.rst - -+ - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - ============ ============================================== - |HDR| **Title:** :ref:`hdrimaging` - - *Compatibility:* > OpenCV 3.0 - - *Author:* Fedor Morozov - - Learn how to create and process high dynamic range images. - - ============ ============================================== - - .. |HDR| image:: images/hdr.png - :height: 90pt - :width: 90pt - -.. raw:: latex - - \pagebreak - -.. toctree:: - :hidden: - - ../hdr_imaging/hdr_imaging diff --git a/doc/tutorials/tutorials.rst b/doc/tutorials/tutorials.rst deleted file mode 100644 index 1b2f4d307e..0000000000 --- a/doc/tutorials/tutorials.rst +++ /dev/null @@ -1,240 +0,0 @@ -################ -OpenCV Tutorials -################ - -The following links describe a set of basic OpenCV tutorials. All the source code mentioned here is provided as part of the OpenCV regular releases, so check before you start copy & pasting the code. The list of tutorials below is automatically generated from reST files located in our GIT repository. - -As always, we would be happy to hear your comments and receive your contributions on any tutorial. - -* :ref:`Table-Of-Content-Introduction` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Introduct| You will learn how to setup OpenCV on your computer! - - =========== ======================================================= - - .. |Introduct| image:: images/introduction.jpg - :height: 80pt - :width: 80pt - :alt: Introduction Icon - -* :ref:`Table-Of-Content-Core` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Core| Here you will learn the about the basic building blocks of the library. A must read and know for understanding how to manipulate the images on a pixel level. - - =========== ======================================================= - - .. |Core| image:: images/core.jpg - :height: 80pt - :width: 80pt - :alt: core Icon - -* :ref:`Table-Of-Content-ImgProc` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |ImgProc| In this section you will learn about the image processing (manipulation) functions inside OpenCV. - - =========== ======================================================= - - .. |ImgProc| image:: images/imgproc.jpg - :height: 80pt - :width: 80pt - :alt: imgproc Icon - -* :ref:`Table-Of-Content-HighGui` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |HighGui| This section contains valuable tutorials about how to read/save your image/video files and how to use the built-in graphical user interface of the library. - - =========== ======================================================= - - .. |HighGui| image:: images/highgui.jpg - :height: 80pt - :width: 80pt - :alt: highgui Icon - -* :ref:`Table-Of-Content-Calib3D` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Calib3D| Although we got most of our images in a 2D format they do come from a 3D world. Here you will learn how to find out from the 2D images information about the 3D world. - - =========== ======================================================= - - .. |Calib3D| image:: images/calib3d.jpg - :height: 80pt - :width: 80pt - :alt: calib3d Icon - -* :ref:`Table-Of-Content-Feature2D` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Featur2D| Learn about how to use the feature points detectors, descriptors and matching framework found inside OpenCV. - - =========== ======================================================= - - .. |Featur2D| image:: images/feature2D.jpg - :height: 80pt - :width: 80pt - :alt: feature2D Icon - -* :ref:`Table-Of-Content-Video` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Video| Look here in order to find algorithms usable on your video streams like: motion extraction, feature tracking and foreground extractions. - - =========== ======================================================= - - .. |Video| image:: images/video.jpg - :height: 80pt - :width: 80pt - :alt: video Icon - -* :ref:`Table-Of-Content-ObjDetect` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |ObjDetect| Ever wondered how your digital camera detects peoples and faces? Look here to find out! - - =========== ======================================================= - - .. |ObjDetect| image:: images/objdetect.jpg - :height: 80pt - :width: 80pt - :alt: objdetect Icon - -* :ref:`Table-Of-Content-Ml` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |ml| Use the powerful machine learning classes for statistical classification, regression and clustering of data. - - =========== ======================================================= - - .. |ml| image:: images/ml.jpg - :height: 80pt - :width: 80pt - :alt: ml Icon - -* :ref:`Table-Of-Content-Photo` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |photo| Use OpenCV for advanced photo processing. - - =========== ======================================================= - - .. |photo| image:: images/photo.png - :height: 80pt - :width: 80pt - :alt: photo Icon - -* :ref:`Table-Of-Content-GPU` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |GPU| Squeeze out every little computation power from your system by using the power of your video card to run the OpenCV algorithms. - - =========== ======================================================= - - .. |GPU| image:: images/gpu.jpg - :height: 80pt - :width: 80pt - :alt: gpu icon - -* :ref:`Table-Of-Content-iOS` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |iOS| Run OpenCV and your vision apps on an iDevice - - =========== ======================================================= - - .. |iOS| image:: images/opencv_ios.png - :height: 80pt - :width: 80pt - :alt: gpu icon - -* :ref:`Table-Of-Content-Viz` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |Viz| These tutorials show how to use Viz module effectively. - - =========== ======================================================= - - .. |Viz| image:: images/viz.jpg - :height: 80pt - :width: 80pt - :alt: viz icon - -* :ref:`Table-Of-Content-General` - - .. tabularcolumns:: m{100pt} m{300pt} - .. cssclass:: toctableopencv - - =========== ======================================================= - |General| These tutorials are the bottom of the iceberg as they link together multiple of the modules presented above in order to solve complex problems. - - =========== ======================================================= - - .. |General| image:: images/general.jpg - :height: 80pt - :width: 80pt - :alt: General Icon - -.. raw:: latex - - \pagebreak - -.. toctree:: - :maxdepth: 2 - :hidden: - - introduction/table_of_content_introduction/table_of_content_introduction - core/table_of_content_core/table_of_content_core - imgproc/table_of_content_imgproc/table_of_content_imgproc - highgui/table_of_content_highgui/table_of_content_highgui - calib3d/table_of_content_calib3d/table_of_content_calib3d - features2d/table_of_content_features2d/table_of_content_features2d - video/table_of_content_video/table_of_content_video - objdetect/table_of_content_objdetect/table_of_content_objdetect - ml/table_of_content_ml/table_of_content_ml - photo/table_of_content_photo/table_of_content_photo - gpu/table_of_content_gpu/table_of_content_gpu - ios/table_of_content_ios/table_of_content_ios - viz/table_of_content_viz/table_of_content_viz - general/table_of_content_general/table_of_content_general diff --git a/doc/tutorials/video/background_subtraction/background_subtraction.markdown b/doc/tutorials/video/background_subtraction/background_subtraction.markdown index 6e425c9f17..760dcab458 100644 --- a/doc/tutorials/video/background_subtraction/background_subtraction.markdown +++ b/doc/tutorials/video/background_subtraction/background_subtraction.markdown @@ -45,7 +45,7 @@ Two different methods are used to generate two foreground masks: -# @ref cv::BackgroundSubtractorMOG2 The results as well as the input data are shown on the screen. -The source file can be downloaded [here ](samples/cpp/tutorial_code/video/bg_sub.cpp). +The source file can be downloaded [here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/video/bg_sub.cpp). @includelineno samples/cpp/tutorial_code/video/bg_sub.cpp diff --git a/doc/tutorials/video/background_subtraction/background_subtraction.rst b/doc/tutorials/video/background_subtraction/background_subtraction.rst deleted file mode 100644 index 0ef5ef5162..0000000000 --- a/doc/tutorials/video/background_subtraction/background_subtraction.rst +++ /dev/null @@ -1,388 +0,0 @@ -.. _Background_Subtraction: - -How to Use Background Subtraction Methods -***************************************** - -* Background subtraction (BS) is a common and widely used technique for generating a foreground mask (namely, a binary image containing the pixels belonging to moving objects in the scene) by using static cameras. - -* As the name suggests, BS calculates the foreground mask performing a subtraction between the current frame and a background model, containing the static part of the scene or, more in general, everything that can be considered as background given the characteristics of the observed scene. - - .. image:: images/Background_Subtraction_Tutorial_Scheme.png - :alt: Background Subtraction - General Scheme - :align: center - -* Background modeling consists of two main steps: - - #. Background Initialization; - #. Background Update. - - In the first step, an initial model of the background is computed, while in the second step that model is updated in order to adapt to possible changes in the scene. - -* In this tutorial we will learn how to perform BS by using OpenCV. As input, we will use data coming from the publicly available data set `Background Models Challenge (BMC) `_ . - -Goals -====== - -In this tutorial you will learn how to: - - #. Read data from videos by using :video_capture:`VideoCapture <>` or image sequences by using :imread:`imread <>`; - #. Create and update the background model by using :background_subtractor:`BackgroundSubtractor <>` class; - #. Get and show the foreground mask by using :imshow:`imshow <>`; - #. Save the output by using :imwrite:`imwrite <>` to quantitatively evaluate the results. - -Code -===== - -In the following you can find the source code. We will let the user chose to process either a video file or a sequence of images. - -* Two different methods are used to generate two foreground masks: - #. :background_subtractor_mog:`MOG <>` - #. :background_subtractor_mog_two:`MOG2 <>` - -The results as well as the input data are shown on the screen. - -.. code-block:: cpp - - //opencv - #include - #include - //C - #include - //C++ - #include - #include - - using namespace cv; - using namespace std; - - //global variables - Mat frame; //current frame - Mat fgMaskMOG; //fg mask generated by MOG method - Mat fgMaskMOG2; //fg mask fg mask generated by MOG2 method - Ptr pMOG; //MOG Background subtractor - Ptr pMOG2; //MOG2 Background subtractor - int keyboard; - - //function declarations - void help(); - void processVideo(char* videoFilename); - void processImages(char* firstFrameFilename); - - void help() - { - cout - << "--------------------------------------------------------------------------" << endl - << "This program shows how to use background subtraction methods provided by " << endl - << " OpenCV. You can process both videos (-vid) and images (-img)." << endl - << endl - << "Usage:" << endl - << "./bs {-vid