mirror of
https://github.com/opencv/opencv.git
synced 2024-11-24 11:10:21 +08:00
Merge pull request #14109 from PedroFerreiradaCosta:adding_python_version_to_anisotropic_tutorial
* Created python version of the code for the anisotropic image segmentation tutorial. Created python/cpp toggles for the markdown file. * fix doxygen warnings
This commit is contained in:
parent
865bd7abff
commit
9cef78b685
@ -48,28 +48,65 @@ The orientation of an anisotropic image:
|
||||
Coherency:
|
||||
\f[C = \frac{\lambda_1 - \lambda_2}{\lambda_1 + \lambda_2}\f]
|
||||
|
||||
The coherency ranges from 0 to 1. For ideal local orientation (\f$\lambda_2\f$ = 0, \f$\lambda_1\f$ > 0) it is one, for an isotropic gray value structure (\f$\lambda_1\f$ = \f$\lambda_2\f$ > 0) it is zero.
|
||||
The coherency ranges from 0 to 1. For ideal local orientation (\f$\lambda_2\f$ = 0, \f$\lambda_1\f$ > 0) it is one, for an isotropic gray value structure (\f$\lambda_1\f$ = \f$\lambda_2\f$ \> 0) it is zero.
|
||||
|
||||
Source code
|
||||
-----------
|
||||
|
||||
You can find source code in the `samples/cpp/tutorial_code/ImgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.cpp` of the OpenCV source code library.
|
||||
|
||||
@add_toggle_cpp
|
||||
@include cpp/tutorial_code/ImgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@include samples/python/tutorial_code/imgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
An anisotropic image segmentation algorithm consists of a gradient structure tensor calculation, an orientation calculation, a coherency calculation and an orientation and coherency thresholding:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.cpp main
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/imgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.py main
|
||||
@end_toggle
|
||||
|
||||
A function calcGST() calculates orientation and coherency by using a gradient structure tensor. An input parameter w defines a window size:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.cpp calcGST
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/imgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.py calcGST
|
||||
@end_toggle
|
||||
|
||||
|
||||
The below code applies a thresholds LowThr and HighThr to image orientation and a threshold C_Thr to image coherency calculated by the previous function. LowThr and HighThr define orientation range:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.cpp thresholding
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/imgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.py thresholding
|
||||
@end_toggle
|
||||
|
||||
|
||||
And finally we combine thresholding results:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.cpp combining
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/imgProc/anisotropic_image_segmentation/anisotropic_image_segmentation.py combining
|
||||
@end_toggle
|
||||
|
||||
|
||||
Result
|
||||
------
|
||||
|
@ -0,0 +1,92 @@
|
||||
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import argparse
|
||||
|
||||
W = 52 # window size is WxW
|
||||
C_Thr = 0.43 # threshold for coherency
|
||||
LowThr = 35 # threshold1 for orientation, it ranges from 0 to 180
|
||||
HighThr = 57 # threshold2 for orientation, it ranges from 0 to 180
|
||||
|
||||
## [calcGST]
|
||||
## [calcJ_header]
|
||||
## [calcGST_proto]
|
||||
def calcGST(inputIMG, w):
|
||||
## [calcGST_proto]
|
||||
img = inputIMG.astype(np.float32)
|
||||
|
||||
# GST components calculation (start)
|
||||
# J = (J11 J12; J12 J22) - GST
|
||||
imgDiffX = cv.Sobel(img, cv.CV_32F, 1, 0, 3)
|
||||
imgDiffY = cv.Sobel(img, cv.CV_32F, 0, 1, 3)
|
||||
imgDiffXY = cv.multiply(imgDiffX, imgDiffY)
|
||||
## [calcJ_header]
|
||||
|
||||
imgDiffXX = cv.multiply(imgDiffX, imgDiffX)
|
||||
imgDiffYY = cv.multiply(imgDiffY, imgDiffY)
|
||||
|
||||
J11 = cv.boxFilter(imgDiffXX, cv.CV_32F, (w,w))
|
||||
J22 = cv.boxFilter(imgDiffYY, cv.CV_32F, (w,w))
|
||||
J12 = cv.boxFilter(imgDiffXY, cv.CV_32F, (w,w))
|
||||
# GST components calculations (stop)
|
||||
|
||||
# eigenvalue calculation (start)
|
||||
# lambda1 = J11 + J22 + sqrt((J11-J22)^2 + 4*J12^2)
|
||||
# lambda2 = J11 + J22 - sqrt((J11-J22)^2 + 4*J12^2)
|
||||
tmp1 = J11 + J22
|
||||
tmp2 = J11 - J22
|
||||
tmp2 = cv.multiply(tmp2, tmp2)
|
||||
tmp3 = cv.multiply(J12, J12)
|
||||
tmp4 = np.sqrt(tmp2 + 4.0 * tmp3)
|
||||
|
||||
lambda1 = tmp1 + tmp4 # biggest eigenvalue
|
||||
lambda2 = tmp1 - tmp4 # smallest eigenvalue
|
||||
# eigenvalue calculation (stop)
|
||||
|
||||
# Coherency calculation (start)
|
||||
# Coherency = (lambda1 - lambda2)/(lambda1 + lambda2)) - measure of anisotropism
|
||||
# Coherency is anisotropy degree (consistency of local orientation)
|
||||
imgCoherencyOut = cv.divide(lambda1 - lambda2, lambda1 + lambda2)
|
||||
# Coherency calculation (stop)
|
||||
|
||||
# orientation angle calculation (start)
|
||||
# tan(2*Alpha) = 2*J12/(J22 - J11)
|
||||
# Alpha = 0.5 atan2(2*J12/(J22 - J11))
|
||||
imgOrientationOut = cv.phase(J22 - J11, 2.0 * J12, angleInDegrees = True)
|
||||
imgOrientationOut = 0.5 * imgOrientationOut
|
||||
# orientation angle calculation (stop)
|
||||
|
||||
return imgCoherencyOut, imgOrientationOut
|
||||
## [calcGST]
|
||||
|
||||
parser = argparse.ArgumentParser(description='Code for Anisotropic image segmentation tutorial.')
|
||||
parser.add_argument('-i', '--input', help='Path to input image.', required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
imgIn = cv.imread(args.input, cv.IMREAD_GRAYSCALE)
|
||||
if imgIn is None:
|
||||
print('Could not open or find the image: {}'.format(args.input))
|
||||
exit(0)
|
||||
|
||||
## [main_extra]
|
||||
## [main]
|
||||
imgCoherency, imgOrientation = calcGST(imgIn, W)
|
||||
|
||||
## [thresholding]
|
||||
_, imgCoherencyBin = cv.threshold(imgCoherency, C_Thr, 255, cv.THRESH_BINARY)
|
||||
_, imgOrientationBin = cv.threshold(imgOrientation, LowThr, HighThr, cv.THRESH_BINARY)
|
||||
## [thresholding]
|
||||
|
||||
## [combining]
|
||||
imgBin = cv.bitwise_and(imgCoherencyBin, imgOrientationBin)
|
||||
## [combining]
|
||||
## [main]
|
||||
|
||||
imgCoherency = cv.normalize(imgCoherency, None, alpha=0, beta=1, norm_type=cv.NORM_MINMAX, dtype=cv.CV_32F)
|
||||
imgOrientation = cv.normalize(imgOrientation, None, alpha=0, beta=1, norm_type=cv.NORM_MINMAX, dtype=cv.CV_32F)
|
||||
|
||||
cv.imshow('result.jpg', np.uint8(0.5*(imgIn + imgBin)))
|
||||
cv.imshow('Coherency.jpg', imgCoherency)
|
||||
cv.imshow('Orientation.jpg', imgOrientation)
|
||||
cv.waitKey(0)
|
||||
## [main_extra]
|
Loading…
Reference in New Issue
Block a user