From 2b550c2f63ebe553b61457488d0bb0bc0a324850 Mon Sep 17 00:00:00 2001 From: meshtag Date: Tue, 12 Jan 2021 17:33:01 +0530 Subject: [PATCH 01/25] Added all standard morphological transformations --- example/morphology.cpp | 175 +++++++++++++++++++++++++++++++++++++++++ example/original.png | Bin 0 -> 2082 bytes 2 files changed, 175 insertions(+) create mode 100644 example/morphology.cpp create mode 100644 example/original.png diff --git a/example/morphology.cpp b/example/morphology.cpp new file mode 100644 index 0000000000..27acd6d795 --- /dev/null +++ b/example/morphology.cpp @@ -0,0 +1,175 @@ +#include +#include +#include +#include +#include +#include + +boost::gil::gray8_image_t img; + +//This function is used for applying basic threshold and convolution operations which are applied +//under the hood for all morphological transformations. +template +boost::gil::gray8_image_t thresh_con_thresh(SrcView const& src_view, Kernel const& ker_mat,const int threshold1,const int threshold2) +{ + using namespace boost::gil; + boost::gil::gray8_image_t intermediate_img(src_view.dimensions()); + threshold_binary(src_view, view(intermediate_img),threshold1, 255); + detail::convolve_2d(view(intermediate_img), ker_mat, view(intermediate_img)); + threshold_binary(const_view(intermediate_img),view(intermediate_img),threshold2,255); + return intermediate_img; +} + +template +boost::gil::gray8_image_t dilate(SrcView const& src_view, Kernel const& ker_mat,const int iterations) +{ + boost::gil::gray8_image_t img_out_dilation(src_view.dimensions()); + img_out_dilation = img; + for(int i=0;i +boost::gil::gray8_image_t erode(SrcView const& src_view, Kernel const& ker_mat,const int iterations) +{ + boost::gil::gray8_image_t img_out_erosion(src_view.dimensions()); + img_out_erosion = img; + for(int i=0;i +boost::gil::gray8_image_t opening(SrcView const& src_view, Kernel const& ker_mat) +{ + boost::gil::gray8_image_t img_out_opening(src_view.dimensions()); + img_out_opening = erode(src_view,ker_mat,1); + return dilate(view(img_out_opening),ker_mat,1); +} + +template +boost::gil::gray8_image_t closing(SrcView const& src_view, Kernel const& ker_mat) +{ + boost::gil::gray8_image_t img_out_closing(src_view.dimensions()); + img_out_closing = dilate(src_view,ker_mat,1); + return erode(view(img_out_closing),ker_mat,1); +} + + +//This function calculates the difference between pixel values of first image_view and second +//image_view.This function can be used for rgb as well as grayscale images. +template +void difference_impl(SrcView const& src_view, DstView const& dst_view, DiffView const& diff_view) +{ + for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) + for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) + diff_view(view_col, view_row) = src_view(view_col,view_row) - dst_view(view_col,view_row); +} + + +template +void difference(SrcView const& src_view, DstView const& dst_view , DiffView const& diff_view) +{ + + BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions()); + + for (std::size_t i = 0; i < src_view.num_channels(); i++) + { + difference_impl( + nth_channel_view(src_view, i), + nth_channel_view(dst_view, i), + nth_channel_view(diff_view, i) + ); + } +} + +template +boost::gil::gray8_image_t morphological_gradient(SrcView const& src_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gray8_image_t int_dilate(src_view.dimensions()),int_erode(src_view.dimensions()),res_image(src_view.dimensions()); + int_dilate = dilate(src_view,ker_mat,1); + int_erode = erode(src_view,ker_mat,1); + difference(view(int_dilate),view(int_erode),view(res_image)); + return res_image; +} + +template +boost::gil::gray8_image_t top_hat(SrcView const& src_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gray8_image_t int_opening(src_view.dimensions()),res_image(src_view.dimensions()); + int_opening = opening(src_view,ker_mat); + difference(src_view,view(int_opening),view(res_image)); + return res_image; +} + +template +boost::gil::gray8_image_t black_hat(SrcView const& src_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gray8_image_t int_closing(src_view.dimensions()),res_image(src_view.dimensions()); + int_closing = closing(src_view,ker_mat); + difference(view(int_closing), src_view,view(res_image)); + return res_image; +} + +//Summary of applied morphological concepts +//Structuring element is SE = [0.1,0.1,0.1] +// |0.1,0.1,0.1| +// [0.1,0.1,0.1] +//SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the +//image to be convolved. +//1.Dilation:If 1 or more bright pixels coincide with the structuring element during convolution, +//center pixel is made bright.We can vary the number of times dilation happens by varying the +//argument 'iterations' in the dilate function. +//2.Erosion:If 8 or more bright pixels coincide with the structuring element during convolution, +//center pixel is made bright.We can vary the number of times erosion happens by varying the +//argument 'iterations' in the erode function. +//3.Opening:Opening is just another name of erosion followed by dilation. +//It is useful in removing noise. +//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. +//5.Morphological Gradient:It is the difference between dilation and erosion of an image. +//The result will look like the outline of the object. +//6.Top Hat:It is the difference between input image and Opening of the image. +//7.Black Hat:It is the difference between the closing of the input image and input image. + +//Functions have been made for applying above morphological transformations which +//return the transformed image. + +int main() +{ + using namespace boost::gil; + read_image("original.png", img, png_tag{}); + std::vectorker_vec(9,0.1f);//Structuring element + detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); + gray8_image_t img_out_dilation(img.dimensions()),img_out_erosion(img.dimensions()),img_out_opening(img.dimensions()); + gray8_image_t img_out_closing(img.dimensions()),img_out_mg(img.dimensions()),img_out_top_hat(img.dimensions()); + gray8_image_t img_out_black_hat(img.dimensions()); + //dilate(input_image_view,structuring_element,iterations) + img_out_dilation = dilate(view(img),ker_mat,1); + //erode(input_image_view,structuring_element,iterations) + img_out_erosion = erode(view(img),ker_mat,1); + //opening(input_image_view,structuring_element) + img_out_opening = opening(view(img),ker_mat); + //closing(input_image_view,structuring_element) + img_out_closing = closing(view(img),ker_mat); + //morphological_gradient(input_image_view,structuring_element) + img_out_mg = morphological_gradient(view(img),ker_mat); + //top_hat(input_image_view,structuring_element) + img_out_top_hat = top_hat(view(img),ker_mat); + //black_hat(input_image_view,structuring_element) + img_out_black_hat = black_hat(view(img),ker_mat); + + //Saving results of above morphological transformations. + write_view("out-morphological-example-dilation.png", view(img_out_dilation), png_tag{}); + write_view("out-morphological-example-erosion.png", view(img_out_erosion), png_tag{}); + write_view("out-morphological-example-opening.png", view(img_out_opening), png_tag{}); + write_view("out-morphological-example-closing.png", view(img_out_closing), png_tag{}); + write_view("out-morphological-example-morphological_gradient.png", view(img_out_mg), png_tag{}); + write_view("out-morphological-example-top_hat.png", view(img_out_top_hat), png_tag{}); + write_view("out-morphological-example-black_hat.png", view(img_out_black_hat), png_tag{}); +} diff --git a/example/original.png b/example/original.png new file mode 100644 index 0000000000000000000000000000000000000000..b63e99ed9da7b769fd4fe45826f1f5118fb24297 GIT binary patch literal 2082 zcmZ8iZB!Fi8U~6e6lgL-Es3HqNe0s5Za%OUTm@l-02eGGm}5C53=p(+p&(Y24~YWK zK(s~zJ5gHBi8NB>s42CDEv14Z@)2P@Srsd~k^)M*T0KZn5ZybR-Tv4gbMJkhdGEdN zecmtn{lpkA521&Xlap7hir5V2d+@7Y0tY9@y4#~pPKzgFi49wdobPnWkNh0%QaSqS zjxOi@^TQ>-X)lhwvGd>?_lTT(es>3(tFzub(NvAy zIzL_N=%N<~u4pLwB>>1_qlr^ZWhdM<)3v6ru8s!PTca3@j-!I7^6GIpP-Cc@kD( zks#cOtGc|>&2*QNl z-@N~ND`WIcdN{QDW0^FG2q~KzompwR+{E4haX$RR>1DIiIl0YWB(C z_K7Nv)~o{Z13a*r3WW%+5Lo54{A?l}lG1*4jQtiQ8u_K%O}9bf&VeyPaBVBRWQ}Qs zRcaUYQyZ?^ztSFH-i`lH+1sWat0O6k$XzgUB>fM9Ywvt#c=&Nxe;Q zW`6;35cEMMAkh`){i+D%Gf-Lt5(%7#o<5a)H5d=XP>OUcwFe3z| z#s^FUXoj)3*|Mn+_*c{U+VTgCs-?@5=ZDgyW1TXt3HUFSpCtNS%?;aAHk~@2XY(~E zb?Rr~%I3JEtJ`P@dCAD=2_RC*sNSX!^z0zGmYLX2K*BgpbTszJ5|9vZQ2JO3I_5mA9KC5A zgw#;RNyoMLQ;NB zuIpv0R2`-J=4=?w6WDnJ^bvQWhrlk(&5n0-5K6yE)k7$R{kyFWDywzyWnvKDGT;jB zA{Uvnq2IQV|9mw4yu10A$t}u@1SflOIQ&177yja<=p+}nuK}^pB1sJhvjm(4G2q$w zsr3EYEf>OXddj@=v%^R~EF+qha?~~oB&pbDZN+efAm9dEFvC>>JXNI7Qp42(?1rdd zVx84*>I=1@ZT9A?m-CCaS~l(MdrGgS&xF5vazET1ruZ=TN?jkdn?AFDekOeXKVV0F u^w54g2gVt>+wmdSAYM%We=~M;&9AKA^Y#TxX!BmK`NwWdB+f=^4*UmVeU2^w literal 0 HcmV?d00001 From 48436fc82ab3d6ffbd2ce13d343640edc54ad02b Mon Sep 17 00:00:00 2001 From: meshtag Date: Thu, 14 Jan 2021 21:49:53 +0530 Subject: [PATCH 02/25] Improved comments and some other things --- example/morphology.cpp | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/example/morphology.cpp b/example/morphology.cpp index 27acd6d795..be27ee52d4 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -5,9 +5,8 @@ #include #include -boost::gil::gray8_image_t img; -//This function is used for applying basic threshold and convolution operations which are applied +//This function is used for applying basic thresholding and convolution operations which are applied //under the hood for all morphological transformations. template boost::gil::gray8_image_t thresh_con_thresh(SrcView const& src_view, Kernel const& ker_mat,const int threshold1,const int threshold2) @@ -20,26 +19,34 @@ boost::gil::gray8_image_t thresh_con_thresh(SrcView const& src_view, Kernel cons return intermediate_img; } +// Dilation:If 1 or more bright pixels coincide with the structuring element during convolution, +// center pixel is made bright.We can vary the number of times dilation happens by varying the +// argument 'iterations' in the dilate function. template boost::gil::gray8_image_t dilate(SrcView const& src_view, Kernel const& ker_mat,const int iterations) { boost::gil::gray8_image_t img_out_dilation(src_view.dimensions()); - img_out_dilation = img; + boost::gil::transform_pixels(src_view,view(img_out_dilation),[](const boost::gil::gray8_pixel_t& p){return p[0];}); for(int i=0;i boost::gil::gray8_image_t erode(SrcView const& src_view, Kernel const& ker_mat,const int iterations) { boost::gil::gray8_image_t img_out_erosion(src_view.dimensions()); - img_out_erosion = img; + boost::gil::transform_pixels(src_view,view(img_out_erosion),[](const boost::gil::gray8_pixel_t& p){return p[0];}); for(int i=0;i boost::gil::gray8_image_t opening(SrcView const& src_view, Kernel const& ker_mat) { @@ -48,6 +55,9 @@ boost::gil::gray8_image_t opening(SrcView const& src_view, Kernel const& ker_mat return dilate(view(img_out_opening),ker_mat,1); } +//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. template boost::gil::gray8_image_t closing(SrcView const& src_view, Kernel const& ker_mat) { @@ -84,6 +94,8 @@ void difference(SrcView const& src_view, DstView const& dst_view , DiffView cons } } +//Morphological Gradient:It is the difference between dilation and erosion of an image. +//The result will look like the outline of the object. template boost::gil::gray8_image_t morphological_gradient(SrcView const& src_view, Kernel const& ker_mat) { @@ -95,6 +107,7 @@ boost::gil::gray8_image_t morphological_gradient(SrcView const& src_view, Kernel return res_image; } +//Top Hat:It is the difference between input image and Opening of the image. template boost::gil::gray8_image_t top_hat(SrcView const& src_view, Kernel const& ker_mat) { @@ -105,6 +118,7 @@ boost::gil::gray8_image_t top_hat(SrcView const& src_view, Kernel const& ker_mat return res_image; } +//Black Hat:It is the difference between the closing of the input image and input image. template boost::gil::gray8_image_t black_hat(SrcView const& src_view, Kernel const& ker_mat) { @@ -115,34 +129,16 @@ boost::gil::gray8_image_t black_hat(SrcView const& src_view, Kernel const& ker_m return res_image; } -//Summary of applied morphological concepts //Structuring element is SE = [0.1,0.1,0.1] // |0.1,0.1,0.1| // [0.1,0.1,0.1] //SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the //image to be convolved. -//1.Dilation:If 1 or more bright pixels coincide with the structuring element during convolution, -//center pixel is made bright.We can vary the number of times dilation happens by varying the -//argument 'iterations' in the dilate function. -//2.Erosion:If 8 or more bright pixels coincide with the structuring element during convolution, -//center pixel is made bright.We can vary the number of times erosion happens by varying the -//argument 'iterations' in the erode function. -//3.Opening:Opening is just another name of erosion followed by dilation. -//It is useful in removing noise. -//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. -//5.Morphological Gradient:It is the difference between dilation and erosion of an image. -//The result will look like the outline of the object. -//6.Top Hat:It is the difference between input image and Opening of the image. -//7.Black Hat:It is the difference between the closing of the input image and input image. - -//Functions have been made for applying above morphological transformations which -//return the transformed image. int main() { using namespace boost::gil; + boost::gil::gray8_image_t img; read_image("original.png", img, png_tag{}); std::vectorker_vec(9,0.1f);//Structuring element detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); From 14900be7116e0002090569a637d4d52928bc0cea Mon Sep 17 00:00:00 2001 From: meshtag Date: Sun, 17 Jan 2021 12:58:55 +0530 Subject: [PATCH 03/25] Applied adviced changes --- example/morphology.cpp | 135 +----------------- .../boost/gil/image_processing/morphology.hpp | 131 +++++++++++++++++ 2 files changed, 135 insertions(+), 131 deletions(-) create mode 100644 include/boost/gil/image_processing/morphology.hpp diff --git a/example/morphology.cpp b/example/morphology.cpp index be27ee52d4..15c4d158a9 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -1,137 +1,10 @@ -#include -#include #include +#include #include -#include -#include - -//This function is used for applying basic thresholding and convolution operations which are applied -//under the hood for all morphological transformations. -template -boost::gil::gray8_image_t thresh_con_thresh(SrcView const& src_view, Kernel const& ker_mat,const int threshold1,const int threshold2) -{ - using namespace boost::gil; - boost::gil::gray8_image_t intermediate_img(src_view.dimensions()); - threshold_binary(src_view, view(intermediate_img),threshold1, 255); - detail::convolve_2d(view(intermediate_img), ker_mat, view(intermediate_img)); - threshold_binary(const_view(intermediate_img),view(intermediate_img),threshold2,255); - return intermediate_img; -} - -// Dilation:If 1 or more bright pixels coincide with the structuring element during convolution, -// center pixel is made bright.We can vary the number of times dilation happens by varying the -// argument 'iterations' in the dilate function. -template -boost::gil::gray8_image_t dilate(SrcView const& src_view, Kernel const& ker_mat,const int iterations) -{ - boost::gil::gray8_image_t img_out_dilation(src_view.dimensions()); - boost::gil::transform_pixels(src_view,view(img_out_dilation),[](const boost::gil::gray8_pixel_t& p){return p[0];}); - for(int i=0;i -boost::gil::gray8_image_t erode(SrcView const& src_view, Kernel const& ker_mat,const int iterations) -{ - boost::gil::gray8_image_t img_out_erosion(src_view.dimensions()); - boost::gil::transform_pixels(src_view,view(img_out_erosion),[](const boost::gil::gray8_pixel_t& p){return p[0];}); - for(int i=0;i -boost::gil::gray8_image_t opening(SrcView const& src_view, Kernel const& ker_mat) -{ - boost::gil::gray8_image_t img_out_opening(src_view.dimensions()); - img_out_opening = erode(src_view,ker_mat,1); - return dilate(view(img_out_opening),ker_mat,1); -} - -//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. -template -boost::gil::gray8_image_t closing(SrcView const& src_view, Kernel const& ker_mat) -{ - boost::gil::gray8_image_t img_out_closing(src_view.dimensions()); - img_out_closing = dilate(src_view,ker_mat,1); - return erode(view(img_out_closing),ker_mat,1); -} - - -//This function calculates the difference between pixel values of first image_view and second -//image_view.This function can be used for rgb as well as grayscale images. -template -void difference_impl(SrcView const& src_view, DstView const& dst_view, DiffView const& diff_view) -{ - for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) - for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) - diff_view(view_col, view_row) = src_view(view_col,view_row) - dst_view(view_col,view_row); -} - - -template -void difference(SrcView const& src_view, DstView const& dst_view , DiffView const& diff_view) -{ - - BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions()); - - for (std::size_t i = 0; i < src_view.num_channels(); i++) - { - difference_impl( - nth_channel_view(src_view, i), - nth_channel_view(dst_view, i), - nth_channel_view(diff_view, i) - ); - } -} - -//Morphological Gradient:It is the difference between dilation and erosion of an image. -//The result will look like the outline of the object. -template -boost::gil::gray8_image_t morphological_gradient(SrcView const& src_view, Kernel const& ker_mat) -{ - using namespace boost::gil; - gray8_image_t int_dilate(src_view.dimensions()),int_erode(src_view.dimensions()),res_image(src_view.dimensions()); - int_dilate = dilate(src_view,ker_mat,1); - int_erode = erode(src_view,ker_mat,1); - difference(view(int_dilate),view(int_erode),view(res_image)); - return res_image; -} - -//Top Hat:It is the difference between input image and Opening of the image. -template -boost::gil::gray8_image_t top_hat(SrcView const& src_view, Kernel const& ker_mat) -{ - using namespace boost::gil; - gray8_image_t int_opening(src_view.dimensions()),res_image(src_view.dimensions()); - int_opening = opening(src_view,ker_mat); - difference(src_view,view(int_opening),view(res_image)); - return res_image; -} - -//Black Hat:It is the difference between the closing of the input image and input image. -template -boost::gil::gray8_image_t black_hat(SrcView const& src_view, Kernel const& ker_mat) -{ - using namespace boost::gil; - gray8_image_t int_closing(src_view.dimensions()),res_image(src_view.dimensions()); - int_closing = closing(src_view,ker_mat); - difference(view(int_closing), src_view,view(res_image)); - return res_image; -} - -//Structuring element is SE = [0.1,0.1,0.1] -// |0.1,0.1,0.1| -// [0.1,0.1,0.1] +//current structuring element is SE = [0.1,0.1,0.1] +// |0.1,0.1,0.1| +// [0.1,0.1,0.1] //SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the //image to be convolved. diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp new file mode 100644 index 0000000000..ee29f9f8d0 --- /dev/null +++ b/include/boost/gil/image_processing/morphology.hpp @@ -0,0 +1,131 @@ +#ifndef BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP +#define BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP + +#include +#include +#include + + +//This function is used for applying basic thresholding and convolution operations which are applied +//under the hood for all morphological transformations. +template +boost::gil::gray8_image_t thresh_con_thresh(SrcView const& src_view, Kernel const& ker_mat,const int threshold1,const int threshold2) +{ + using namespace boost::gil; + boost::gil::gray8_image_t intermediate_img(src_view.dimensions()); + threshold_binary(src_view, view(intermediate_img),threshold1, 255); + detail::convolve_2d(view(intermediate_img), ker_mat, view(intermediate_img)); + threshold_binary(const_view(intermediate_img),view(intermediate_img),threshold2,255); + return intermediate_img; +} + +// Dilation:If 1 or more bright pixels coincide with the structuring element during convolution, +// center pixel is made bright.We can vary the number of times dilation happens by varying the +// argument 'iterations' in the dilate function. +template +boost::gil::gray8_image_t dilate(SrcView const& src_view, Kernel const& ker_mat,const int iterations) +{ + boost::gil::gray8_image_t img_out_dilation(src_view.dimensions()); + boost::gil::transform_pixels(src_view,view(img_out_dilation),[](const boost::gil::gray8_pixel_t& p){return p[0];}); + for(int i=0;i +boost::gil::gray8_image_t erode(SrcView const& src_view, Kernel const& ker_mat,const int iterations) +{ + boost::gil::gray8_image_t img_out_erosion(src_view.dimensions()); + boost::gil::transform_pixels(src_view,view(img_out_erosion),[](const boost::gil::gray8_pixel_t& p){return p[0];}); + for(int i=0;i +boost::gil::gray8_image_t opening(SrcView const& src_view, Kernel const& ker_mat) +{ + boost::gil::gray8_image_t img_out_opening(src_view.dimensions()); + img_out_opening = erode(src_view,ker_mat,1); + return dilate(view(img_out_opening),ker_mat,1); +} + +//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. +template +boost::gil::gray8_image_t closing(SrcView const& src_view, Kernel const& ker_mat) +{ + boost::gil::gray8_image_t img_out_closing(src_view.dimensions()); + img_out_closing = dilate(src_view,ker_mat,1); + return erode(view(img_out_closing),ker_mat,1); +} + + +//This function calculates the difference between pixel values of first image_view and second +//image_view.This function can be used for rgb as well as grayscale images. +template +void difference_impl(SrcView const& src_view, DstView const& dst_view, DiffView const& diff_view) +{ + for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) + for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) + diff_view(view_col, view_row) = src_view(view_col,view_row) - dst_view(view_col,view_row); +} + + +template +void difference(SrcView const& src_view, DstView const& dst_view , DiffView const& diff_view) +{ + + BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions()); + + for (std::size_t i = 0; i < src_view.num_channels(); i++) + { + difference_impl( + nth_channel_view(src_view, i), + nth_channel_view(dst_view, i), + nth_channel_view(diff_view, i) + ); + } +} + +//Morphological Gradient:It is the difference between dilation and erosion of an image. +//The result will look like the outline of the object. +template +boost::gil::gray8_image_t morphological_gradient(SrcView const& src_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gray8_image_t int_dilate(src_view.dimensions()),int_erode(src_view.dimensions()),res_image(src_view.dimensions()); + int_dilate = dilate(src_view,ker_mat,1); + int_erode = erode(src_view,ker_mat,1); + difference(view(int_dilate),view(int_erode),view(res_image)); + return res_image; +} + +//Top Hat:It is the difference between input image and Opening of the image. +template +boost::gil::gray8_image_t top_hat(SrcView const& src_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gray8_image_t int_opening(src_view.dimensions()),res_image(src_view.dimensions()); + int_opening = opening(src_view,ker_mat); + difference(src_view,view(int_opening),view(res_image)); + return res_image; +} + +//Black Hat:It is the difference between the closing of the input image and input image. +template +boost::gil::gray8_image_t black_hat(SrcView const& src_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gray8_image_t int_closing(src_view.dimensions()),res_image(src_view.dimensions()); + int_closing = closing(src_view,ker_mat); + difference(view(int_closing), src_view,view(res_image)); + return res_image; +} +#endif //BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP \ No newline at end of file From 53d92b28451757a05a5043cdac1e9e96b13b3740 Mon Sep 17 00:00:00 2001 From: meshtag Date: Sun, 17 Jan 2021 13:00:00 +0530 Subject: [PATCH 04/25] Applied adviced changes --- example/morphology.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/morphology.cpp b/example/morphology.cpp index 15c4d158a9..304e409147 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -6,7 +6,7 @@ // |0.1,0.1,0.1| // [0.1,0.1,0.1] //SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the -//image to be convolved. +//image to be convolved. The structuring element can be easily changed by the user. int main() { From 6ac3102cec60370f6e7ce590bacf0d1a591f3010 Mon Sep 17 00:00:00 2001 From: meshtag Date: Wed, 20 Jan 2021 17:05:51 +0530 Subject: [PATCH 05/25] Should handle grayscale dilation/erosion --- example/morphology.cpp | 14 ++-- .../boost/gil/image_processing/morphology.hpp | 70 +++++++++++++++---- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/example/morphology.cpp b/example/morphology.cpp index 304e409147..dcd0a17030 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -2,9 +2,9 @@ #include #include -//current structuring element is SE = [0.1,0.1,0.1] -// |0.1,0.1,0.1| -// [0.1,0.1,0.1] +//Default structuring element is SE = [1,1,1] +// |1,1,1| +// [1,1,1] //SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the //image to be convolved. The structuring element can be easily changed by the user. @@ -13,7 +13,13 @@ int main() using namespace boost::gil; boost::gil::gray8_image_t img; read_image("original.png", img, png_tag{}); - std::vectorker_vec(9,0.1f);//Structuring element + + //Image can be converted to a binary format with high value as 255 and low value as 0 + //by uncommenting the following threshold operator.This can be used for binary morphological + //operations. + threshold_binary(view(img), view(img),170, 255); + + std::vectorker_vec(9,1.0f);//Structuring element detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); gray8_image_t img_out_dilation(img.dimensions()),img_out_erosion(img.dimensions()),img_out_opening(img.dimensions()); gray8_image_t img_out_closing(img.dimensions()),img_out_mg(img.dimensions()),img_out_top_hat(img.dimensions()); diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index ee29f9f8d0..2bd1c20c2e 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -1,26 +1,68 @@ #ifndef BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP #define BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP -#include #include -#include +template +void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel,const int identifier) +{ + int flip_ker_row, flip_ker_col, row_boundary, col_boundary; + int max_overlapped_element,min_overlapped_element; + for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) + { + for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) + { + max_overlapped_element = 0,min_overlapped_element = 256; + for (std::size_t kernel_row = 0; kernel_row < kernel.size(); ++kernel_row) + { + flip_ker_row = kernel.size() - 1 - kernel_row; // row index of flipped kernel + + for (std::size_t kernel_col = 0; kernel_col < kernel.size(); ++kernel_col) + { + flip_ker_col = kernel.size() - 1 - kernel_col; // column index of flipped kernel + + // index of input signal, used for checking boundary + row_boundary = view_row + (kernel.center_y() - flip_ker_row); + col_boundary = view_col + (kernel.center_x() - flip_ker_col); + + // ignore input samples which are out of bound + if (row_boundary >= 0 && row_boundary < src_view.height() && + col_boundary >= 0 && col_boundary < src_view.width()) + { + if(src_view(col_boundary, row_boundary) > max_overlapped_element) + max_overlapped_element = src_view(col_boundary, row_boundary); + if(src_view(col_boundary, row_boundary) < min_overlapped_element) + min_overlapped_element = src_view(col_boundary, row_boundary); + } + } + } + if(identifier)//identifier = 1 for dilation + dst_view(view_col, view_row) = max_overlapped_element; + else //identifier = 0 for erosion + dst_view(view_col, view_row) = min_overlapped_element; + } + } +} -//This function is used for applying basic thresholding and convolution operations which are applied -//under the hood for all morphological transformations. template -boost::gil::gray8_image_t thresh_con_thresh(SrcView const& src_view, Kernel const& ker_mat,const int threshold1,const int threshold2) +boost::gil::gray8_image_t morph(SrcView const& src_view, Kernel const& ker_mat,const int identifier) { using namespace boost::gil; + BOOST_ASSERT(ker_mat.size() != 0); boost::gil::gray8_image_t intermediate_img(src_view.dimensions()); - threshold_binary(src_view, view(intermediate_img),threshold1, 255); - detail::convolve_2d(view(intermediate_img), ker_mat, view(intermediate_img)); - threshold_binary(const_view(intermediate_img),view(intermediate_img),threshold2,255); + for (std::size_t i = 0; i < src_view.num_channels(); i++) + { + morph_impl( + nth_channel_view(src_view, i), + nth_channel_view(view(intermediate_img), i), + ker_mat,identifier + ); + } return intermediate_img; } -// Dilation:If 1 or more bright pixels coincide with the structuring element during convolution, -// center pixel is made bright.We can vary the number of times dilation happens by varying the +// Dilation:Give the maximum overlapped value to the pixel overlapping with the center element of +//structuring element.We can vary the number of times dilation happens by varying the // argument 'iterations' in the dilate function. template boost::gil::gray8_image_t dilate(SrcView const& src_view, Kernel const& ker_mat,const int iterations) @@ -28,12 +70,12 @@ boost::gil::gray8_image_t dilate(SrcView const& src_view, Kernel const& ker_mat, boost::gil::gray8_image_t img_out_dilation(src_view.dimensions()); boost::gil::transform_pixels(src_view,view(img_out_dilation),[](const boost::gil::gray8_pixel_t& p){return p[0];}); for(int i=0;i boost::gil::gray8_image_t erode(SrcView const& src_view, Kernel const& ker_mat,const int iterations) @@ -41,7 +83,7 @@ boost::gil::gray8_image_t erode(SrcView const& src_view, Kernel const& ker_mat,c boost::gil::gray8_image_t img_out_erosion(src_view.dimensions()); boost::gil::transform_pixels(src_view,view(img_out_erosion),[](const boost::gil::gray8_pixel_t& p){return p[0];}); for(int i=0;i Date: Fri, 22 Jan 2021 00:58:18 +0530 Subject: [PATCH 06/25] Checking --- example/morphology.cpp | 50 ----- example/original.png | Bin 2082 -> 0 bytes .../boost/gil/image_processing/morphology.hpp | 173 ------------------ 3 files changed, 223 deletions(-) delete mode 100644 example/morphology.cpp delete mode 100644 example/original.png delete mode 100644 include/boost/gil/image_processing/morphology.hpp diff --git a/example/morphology.cpp b/example/morphology.cpp deleted file mode 100644 index dcd0a17030..0000000000 --- a/example/morphology.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include - -//Default structuring element is SE = [1,1,1] -// |1,1,1| -// [1,1,1] -//SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the -//image to be convolved. The structuring element can be easily changed by the user. - -int main() -{ - using namespace boost::gil; - boost::gil::gray8_image_t img; - read_image("original.png", img, png_tag{}); - - //Image can be converted to a binary format with high value as 255 and low value as 0 - //by uncommenting the following threshold operator.This can be used for binary morphological - //operations. - threshold_binary(view(img), view(img),170, 255); - - std::vectorker_vec(9,1.0f);//Structuring element - detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); - gray8_image_t img_out_dilation(img.dimensions()),img_out_erosion(img.dimensions()),img_out_opening(img.dimensions()); - gray8_image_t img_out_closing(img.dimensions()),img_out_mg(img.dimensions()),img_out_top_hat(img.dimensions()); - gray8_image_t img_out_black_hat(img.dimensions()); - //dilate(input_image_view,structuring_element,iterations) - img_out_dilation = dilate(view(img),ker_mat,1); - //erode(input_image_view,structuring_element,iterations) - img_out_erosion = erode(view(img),ker_mat,1); - //opening(input_image_view,structuring_element) - img_out_opening = opening(view(img),ker_mat); - //closing(input_image_view,structuring_element) - img_out_closing = closing(view(img),ker_mat); - //morphological_gradient(input_image_view,structuring_element) - img_out_mg = morphological_gradient(view(img),ker_mat); - //top_hat(input_image_view,structuring_element) - img_out_top_hat = top_hat(view(img),ker_mat); - //black_hat(input_image_view,structuring_element) - img_out_black_hat = black_hat(view(img),ker_mat); - - //Saving results of above morphological transformations. - write_view("out-morphological-example-dilation.png", view(img_out_dilation), png_tag{}); - write_view("out-morphological-example-erosion.png", view(img_out_erosion), png_tag{}); - write_view("out-morphological-example-opening.png", view(img_out_opening), png_tag{}); - write_view("out-morphological-example-closing.png", view(img_out_closing), png_tag{}); - write_view("out-morphological-example-morphological_gradient.png", view(img_out_mg), png_tag{}); - write_view("out-morphological-example-top_hat.png", view(img_out_top_hat), png_tag{}); - write_view("out-morphological-example-black_hat.png", view(img_out_black_hat), png_tag{}); -} diff --git a/example/original.png b/example/original.png deleted file mode 100644 index b63e99ed9da7b769fd4fe45826f1f5118fb24297..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2082 zcmZ8iZB!Fi8U~6e6lgL-Es3HqNe0s5Za%OUTm@l-02eGGm}5C53=p(+p&(Y24~YWK zK(s~zJ5gHBi8NB>s42CDEv14Z@)2P@Srsd~k^)M*T0KZn5ZybR-Tv4gbMJkhdGEdN zecmtn{lpkA521&Xlap7hir5V2d+@7Y0tY9@y4#~pPKzgFi49wdobPnWkNh0%QaSqS zjxOi@^TQ>-X)lhwvGd>?_lTT(es>3(tFzub(NvAy zIzL_N=%N<~u4pLwB>>1_qlr^ZWhdM<)3v6ru8s!PTca3@j-!I7^6GIpP-Cc@kD( zks#cOtGc|>&2*QNl z-@N~ND`WIcdN{QDW0^FG2q~KzompwR+{E4haX$RR>1DIiIl0YWB(C z_K7Nv)~o{Z13a*r3WW%+5Lo54{A?l}lG1*4jQtiQ8u_K%O}9bf&VeyPaBVBRWQ}Qs zRcaUYQyZ?^ztSFH-i`lH+1sWat0O6k$XzgUB>fM9Ywvt#c=&Nxe;Q zW`6;35cEMMAkh`){i+D%Gf-Lt5(%7#o<5a)H5d=XP>OUcwFe3z| z#s^FUXoj)3*|Mn+_*c{U+VTgCs-?@5=ZDgyW1TXt3HUFSpCtNS%?;aAHk~@2XY(~E zb?Rr~%I3JEtJ`P@dCAD=2_RC*sNSX!^z0zGmYLX2K*BgpbTszJ5|9vZQ2JO3I_5mA9KC5A zgw#;RNyoMLQ;NB zuIpv0R2`-J=4=?w6WDnJ^bvQWhrlk(&5n0-5K6yE)k7$R{kyFWDywzyWnvKDGT;jB zA{Uvnq2IQV|9mw4yu10A$t}u@1SflOIQ&177yja<=p+}nuK}^pB1sJhvjm(4G2q$w zsr3EYEf>OXddj@=v%^R~EF+qha?~~oB&pbDZN+efAm9dEFvC>>JXNI7Qp42(?1rdd zVx84*>I=1@ZT9A?m-CCaS~l(MdrGgS&xF5vazET1ruZ=TN?jkdn?AFDekOeXKVV0F u^w54g2gVt>+wmdSAYM%We=~M;&9AKA^Y#TxX!BmK`NwWdB+f=^4*UmVeU2^w diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp deleted file mode 100644 index 2bd1c20c2e..0000000000 --- a/include/boost/gil/image_processing/morphology.hpp +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP -#define BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP - -#include - -template -void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel,const int identifier) -{ - int flip_ker_row, flip_ker_col, row_boundary, col_boundary; - int max_overlapped_element,min_overlapped_element; - for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) - { - for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) - { - max_overlapped_element = 0,min_overlapped_element = 256; - for (std::size_t kernel_row = 0; kernel_row < kernel.size(); ++kernel_row) - { - flip_ker_row = kernel.size() - 1 - kernel_row; // row index of flipped kernel - - for (std::size_t kernel_col = 0; kernel_col < kernel.size(); ++kernel_col) - { - flip_ker_col = kernel.size() - 1 - kernel_col; // column index of flipped kernel - - // index of input signal, used for checking boundary - row_boundary = view_row + (kernel.center_y() - flip_ker_row); - col_boundary = view_col + (kernel.center_x() - flip_ker_col); - - // ignore input samples which are out of bound - if (row_boundary >= 0 && row_boundary < src_view.height() && - col_boundary >= 0 && col_boundary < src_view.width()) - { - if(src_view(col_boundary, row_boundary) > max_overlapped_element) - max_overlapped_element = src_view(col_boundary, row_boundary); - if(src_view(col_boundary, row_boundary) < min_overlapped_element) - min_overlapped_element = src_view(col_boundary, row_boundary); - } - } - } - if(identifier)//identifier = 1 for dilation - dst_view(view_col, view_row) = max_overlapped_element; - else //identifier = 0 for erosion - dst_view(view_col, view_row) = min_overlapped_element; - } - } -} - -template -boost::gil::gray8_image_t morph(SrcView const& src_view, Kernel const& ker_mat,const int identifier) -{ - using namespace boost::gil; - BOOST_ASSERT(ker_mat.size() != 0); - boost::gil::gray8_image_t intermediate_img(src_view.dimensions()); - for (std::size_t i = 0; i < src_view.num_channels(); i++) - { - morph_impl( - nth_channel_view(src_view, i), - nth_channel_view(view(intermediate_img), i), - ker_mat,identifier - ); - } - return intermediate_img; -} - -// Dilation:Give the maximum overlapped value to the pixel overlapping with the center element of -//structuring element.We can vary the number of times dilation happens by varying the -// argument 'iterations' in the dilate function. -template -boost::gil::gray8_image_t dilate(SrcView const& src_view, Kernel const& ker_mat,const int iterations) -{ - boost::gil::gray8_image_t img_out_dilation(src_view.dimensions()); - boost::gil::transform_pixels(src_view,view(img_out_dilation),[](const boost::gil::gray8_pixel_t& p){return p[0];}); - for(int i=0;i -boost::gil::gray8_image_t erode(SrcView const& src_view, Kernel const& ker_mat,const int iterations) -{ - boost::gil::gray8_image_t img_out_erosion(src_view.dimensions()); - boost::gil::transform_pixels(src_view,view(img_out_erosion),[](const boost::gil::gray8_pixel_t& p){return p[0];}); - for(int i=0;i -boost::gil::gray8_image_t opening(SrcView const& src_view, Kernel const& ker_mat) -{ - boost::gil::gray8_image_t img_out_opening(src_view.dimensions()); - img_out_opening = erode(src_view,ker_mat,1); - return dilate(view(img_out_opening),ker_mat,1); -} - -//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. -template -boost::gil::gray8_image_t closing(SrcView const& src_view, Kernel const& ker_mat) -{ - boost::gil::gray8_image_t img_out_closing(src_view.dimensions()); - img_out_closing = dilate(src_view,ker_mat,1); - return erode(view(img_out_closing),ker_mat,1); -} - - -//This function calculates the difference between pixel values of first image_view and second -//image_view.This function can be used for rgb as well as grayscale images. -template -void difference_impl(SrcView const& src_view, DstView const& dst_view, DiffView const& diff_view) -{ - for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) - for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) - diff_view(view_col, view_row) = src_view(view_col,view_row) - dst_view(view_col,view_row); -} - - -template -void difference(SrcView const& src_view, DstView const& dst_view , DiffView const& diff_view) -{ - - BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions()); - - for (std::size_t i = 0; i < src_view.num_channels(); i++) - { - difference_impl( - nth_channel_view(src_view, i), - nth_channel_view(dst_view, i), - nth_channel_view(diff_view, i) - ); - } -} - -//Morphological Gradient:It is the difference between dilation and erosion of an image. -//The result will look like the outline of the object. -template -boost::gil::gray8_image_t morphological_gradient(SrcView const& src_view, Kernel const& ker_mat) -{ - using namespace boost::gil; - gray8_image_t int_dilate(src_view.dimensions()),int_erode(src_view.dimensions()),res_image(src_view.dimensions()); - int_dilate = dilate(src_view,ker_mat,1); - int_erode = erode(src_view,ker_mat,1); - difference(view(int_dilate),view(int_erode),view(res_image)); - return res_image; -} - -//Top Hat:It is the difference between input image and Opening of the image. -template -boost::gil::gray8_image_t top_hat(SrcView const& src_view, Kernel const& ker_mat) -{ - using namespace boost::gil; - gray8_image_t int_opening(src_view.dimensions()),res_image(src_view.dimensions()); - int_opening = opening(src_view,ker_mat); - difference(src_view,view(int_opening),view(res_image)); - return res_image; -} - -//Black Hat:It is the difference between the closing of the input image and input image. -template -boost::gil::gray8_image_t black_hat(SrcView const& src_view, Kernel const& ker_mat) -{ - using namespace boost::gil; - gray8_image_t int_closing(src_view.dimensions()),res_image(src_view.dimensions()); - int_closing = closing(src_view,ker_mat); - difference(view(int_closing), src_view,view(res_image)); - return res_image; -} -#endif //BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP \ No newline at end of file From d3897e7115a6973a1e4211b52d9114da4f0430a4 Mon Sep 17 00:00:00 2001 From: meshtag Date: Fri, 22 Jan 2021 01:16:42 +0530 Subject: [PATCH 07/25] Added test cases and improved code structure --- example/morphology.cpp | 58 ++++++ example/original.png | Bin 0 -> 2082 bytes .../boost/gil/image_processing/morphology.hpp | 193 ++++++++++++++++++ test/core/image_processing/CMakeLists.txt | 1 + test/core/image_processing/morphology.cpp | 137 +++++++++++++ 5 files changed, 389 insertions(+) create mode 100644 example/morphology.cpp create mode 100644 example/original.png create mode 100644 include/boost/gil/image_processing/morphology.hpp create mode 100644 test/core/image_processing/morphology.cpp diff --git a/example/morphology.cpp b/example/morphology.cpp new file mode 100644 index 0000000000..f711fc7eb9 --- /dev/null +++ b/example/morphology.cpp @@ -0,0 +1,58 @@ +// +// Copyright 2021 Prathamesh Tagore +// +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include +#include + +//Default structuring element is SE = [1,1,1] +// |1,1,1| +// [1,1,1] +//SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the +//image to be convolved. The structuring element can be easily changed by the user. + +int main() +{ + using namespace boost::gil; + gray8_image_t img; + read_image("original.png", img, png_tag{}); + + //Image can be converted to a binary format with high value as 255 and low value as 0 + //by uncommenting the following threshold operator.This can be used for binary morphological + //operations.Convenient threshold for binary conversion should be chosen by the user. + //threshold_binary(view(img), view(img),170, 255); + + std::vectorker_vec(9,1.0f);//Structuring element + detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); + gray8_image_t img_out_dilation(img.dimensions()),img_out_erosion(img.dimensions()),img_out_opening(img.dimensions()); + gray8_image_t img_out_closing(img.dimensions()),img_out_mg(img.dimensions()),img_out_top_hat(img.dimensions()); + gray8_image_t img_out_black_hat(img.dimensions()); + //dilate(input_image_view,structuring_element,iterations) + dilate(view(img),view(img_out_dilation),ker_mat,1); + //erode(input_image_view,structuring_element,iterations) + erode(view(img),view(img_out_erosion),ker_mat,1); + //opening(input_image_view,structuring_element) + opening(view(img),view(img_out_opening),ker_mat); + //closing(input_image_view,structuring_element) + closing(view(img),view(img_out_closing),ker_mat); + //morphological_gradient(input_image_view,structuring_element) + morphological_gradient(view(img),view(img_out_mg),ker_mat); + //top_hat(input_image_view,structuring_element) + top_hat(view(img),view(img_out_top_hat),ker_mat); + //black_hat(input_image_view,structuring_element) + black_hat(view(img),view(img_out_black_hat),ker_mat); + + //Saving results of above morphological transformations. + write_view("out-morphological-example-dilation.png", view(img_out_dilation), png_tag{}); + write_view("out-morphological-example-erosion.png", view(img_out_erosion), png_tag{}); + write_view("out-morphological-example-opening.png", view(img_out_opening), png_tag{}); + write_view("out-morphological-example-closing.png", view(img_out_closing), png_tag{}); + write_view("out-morphological-example-morphological_gradient.png", view(img_out_mg), png_tag{}); + write_view("out-morphological-example-top_hat.png", view(img_out_top_hat), png_tag{}); + write_view("out-morphological-example-black_hat.png", view(img_out_black_hat), png_tag{}); +} diff --git a/example/original.png b/example/original.png new file mode 100644 index 0000000000000000000000000000000000000000..b63e99ed9da7b769fd4fe45826f1f5118fb24297 GIT binary patch literal 2082 zcmZ8iZB!Fi8U~6e6lgL-Es3HqNe0s5Za%OUTm@l-02eGGm}5C53=p(+p&(Y24~YWK zK(s~zJ5gHBi8NB>s42CDEv14Z@)2P@Srsd~k^)M*T0KZn5ZybR-Tv4gbMJkhdGEdN zecmtn{lpkA521&Xlap7hir5V2d+@7Y0tY9@y4#~pPKzgFi49wdobPnWkNh0%QaSqS zjxOi@^TQ>-X)lhwvGd>?_lTT(es>3(tFzub(NvAy zIzL_N=%N<~u4pLwB>>1_qlr^ZWhdM<)3v6ru8s!PTca3@j-!I7^6GIpP-Cc@kD( zks#cOtGc|>&2*QNl z-@N~ND`WIcdN{QDW0^FG2q~KzompwR+{E4haX$RR>1DIiIl0YWB(C z_K7Nv)~o{Z13a*r3WW%+5Lo54{A?l}lG1*4jQtiQ8u_K%O}9bf&VeyPaBVBRWQ}Qs zRcaUYQyZ?^ztSFH-i`lH+1sWat0O6k$XzgUB>fM9Ywvt#c=&Nxe;Q zW`6;35cEMMAkh`){i+D%Gf-Lt5(%7#o<5a)H5d=XP>OUcwFe3z| z#s^FUXoj)3*|Mn+_*c{U+VTgCs-?@5=ZDgyW1TXt3HUFSpCtNS%?;aAHk~@2XY(~E zb?Rr~%I3JEtJ`P@dCAD=2_RC*sNSX!^z0zGmYLX2K*BgpbTszJ5|9vZQ2JO3I_5mA9KC5A zgw#;RNyoMLQ;NB zuIpv0R2`-J=4=?w6WDnJ^bvQWhrlk(&5n0-5K6yE)k7$R{kyFWDywzyWnvKDGT;jB zA{Uvnq2IQV|9mw4yu10A$t}u@1SflOIQ&177yja<=p+}nuK}^pB1sJhvjm(4G2q$w zsr3EYEf>OXddj@=v%^R~EF+qha?~~oB&pbDZN+efAm9dEFvC>>JXNI7Qp42(?1rdd zVx84*>I=1@ZT9A?m-CCaS~l(MdrGgS&xF5vazET1ruZ=TN?jkdn?AFDekOeXKVV0F u^w54g2gVt>+wmdSAYM%We=~M;&9AKA^Y#TxX!BmK`NwWdB+f=^4*UmVeU2^w literal 0 HcmV?d00001 diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp new file mode 100644 index 0000000000..a46318a0ed --- /dev/null +++ b/include/boost/gil/image_processing/morphology.hpp @@ -0,0 +1,193 @@ +// +// Copyright 2021 Prathamesh Tagore +// +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP +#define BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP + +#include + +#include +#include +#include +#include + +namespace gil = boost::gil; +namespace boost{ + namespace gil{ + enum class morphological_operations + { + dilate, + erode, + opening, + closing, + morphological_gradient, + top_hat, + black_hat + }; +namespace detail{ +template +void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel,const int identifier) +{ + int flip_ker_row, flip_ker_col, row_boundary, col_boundary; + typename channel_type::type max_overlapped_element,min_overlapped_element; + for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) + { + for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) + { + max_overlapped_element = (std::numeric_limits::type>::min)(); + min_overlapped_element = (std::numeric_limits::type>::max)(); + for (std::size_t kernel_row = 0; kernel_row < kernel.size(); ++kernel_row) + { + flip_ker_row = kernel.size() - 1 - kernel_row; // row index of flipped kernel + + for (std::size_t kernel_col = 0; kernel_col < kernel.size(); ++kernel_col) + { + flip_ker_col = kernel.size() - 1 - kernel_col; // column index of flipped kernel + + // index of input signal, used for checking boundary + row_boundary = view_row + (kernel.center_y() - flip_ker_row); + col_boundary = view_col + (kernel.center_x() - flip_ker_col); + + // ignore input samples which are out of bound + if (row_boundary >= 0 && row_boundary < src_view.height() && + col_boundary >= 0 && col_boundary < src_view.width()) + { + if(src_view(col_boundary, row_boundary) > max_overlapped_element) + max_overlapped_element = src_view(col_boundary, row_boundary); + if(src_view(col_boundary, row_boundary) < min_overlapped_element) + min_overlapped_element = src_view(col_boundary, row_boundary); + } + } + } + if(identifier)//identifier = 1 for dilation + dst_view(view_col, view_row) = max_overlapped_element; + else //identifier = 0 for erosion + dst_view(view_col, view_row) = min_overlapped_element; + } + } + } + +template +void morph(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_mat,const int identifier) +{ + using namespace boost::gil; + BOOST_ASSERT(ker_mat.size() != 0 && src_view.dimensions() == dst_view.dimensions()); + gil::gray8_image_t intermediate_img(src_view.dimensions()); + for (std::size_t i = 0; i < src_view.num_channels(); i++) + { + morph_impl( + nth_channel_view(src_view, i), + nth_channel_view(view(intermediate_img), i), + ker_mat,identifier + ); + } + gil::transform_pixels(view(intermediate_img),dst_view,[](const gil::gray8_pixel_t& p){return p[0];}); +} + +//This function calculates the difference between pixel values of first image_view and second +//image_view.This function can be used for rgb as well as grayscale images. +template +void difference_impl(SrcView const& src_view, DstView const& dst_view, DiffView const& diff_view) +{ + for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) + for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) + diff_view(view_col, view_row) = src_view(view_col,view_row) - dst_view(view_col,view_row); +} + +template +void difference(SrcView const& src_view, DstView const& dst_view , DiffView const& diff_view) +{ + + BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions()); + + for (std::size_t i = 0; i < src_view.num_channels(); i++) + { + difference_impl( + nth_channel_view(src_view, i), + nth_channel_view(dst_view, i), + nth_channel_view(diff_view, i) + ); + } +} +}//namespace boost::gil::detail + +// Dilation:Give the maximum overlapped value to the pixel overlapping with the center element of +//structuring element.We can vary the number of times dilation happens by varying the +// argument 'iterations' in the dilate function. +template +void dilate(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_mat,const int iterations) +{ + boost::gil::transform_pixels(src_view,dst_view,[](const boost::gil::gray8_pixel_t& p){return p[0];}); + for(int i=0;i +void erode(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_mat,const int iterations) +{ + boost::gil::transform_pixels(src_view,dst_view,[](const boost::gil::gray8_pixel_t& p){return p[0];}); + for(int i=0;i +void opening(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_mat) +{ + erode(src_view,dst_view,ker_mat,1); + dilate(dst_view,dst_view,ker_mat,1); +} + +//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. +template +void closing(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_mat) +{ + dilate(src_view,dst_view,ker_mat,1); + erode(dst_view,dst_view,ker_mat,1); +} + +//Morphological Gradient:It is the difference between dilation and erosion of an image. +//The result will look like the outline of the object. +template +void morphological_gradient(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gray8_image_t int_dilate(src_view.dimensions()),int_erode(src_view.dimensions()); + dilate(src_view,view(int_dilate),ker_mat,1); + erode(src_view,view(int_erode),ker_mat,1); + difference(view(int_dilate),view(int_erode),dst_view); +} + +//Top Hat:It is the difference between input image and Opening of the image. +template +void top_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gray8_image_t int_opening(src_view.dimensions()); + opening(src_view,view(int_opening),ker_mat); + difference(src_view,view(int_opening),dst_view); +} + +//Black Hat:It is the difference between the closing of the input image and input image. +template +void black_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gray8_image_t int_closing(src_view.dimensions()); + closing(src_view,view(int_closing),ker_mat); + difference(view(int_closing), src_view,dst_view); +} + } +}//namespace boost::gil +#endif //BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP diff --git a/test/core/image_processing/CMakeLists.txt b/test/core/image_processing/CMakeLists.txt index 5ecd590629..80f9b61afb 100644 --- a/test/core/image_processing/CMakeLists.txt +++ b/test/core/image_processing/CMakeLists.txt @@ -7,6 +7,7 @@ # http://www.boost.org/LICENSE_1_0.txt) # foreach(_name + morphology threshold_binary threshold_truncate threshold_otsu) diff --git a/test/core/image_processing/morphology.cpp b/test/core/image_processing/morphology.cpp new file mode 100644 index 0000000000..5e8fc9a601 --- /dev/null +++ b/test/core/image_processing/morphology.cpp @@ -0,0 +1,137 @@ +// +// Copyright 2021 Prathamesh Tagore +// +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include +#include + +namespace gil = boost::gil; + +void pixel_fill(std::vector > &original_binary_vector, boost::gil::gray8_image_t &original_img) +{ + for (std::ptrdiff_t view_row = 0; view_row < view(original_img).height(); ++view_row) + { + for (std::ptrdiff_t view_col = 0; view_col < view(original_img).width(); ++view_col) + { + view(original_img)(view_col,view_row) = gil::gray8_pixel_t(original_binary_vector[view_row][view_col]); + } + } +} + +int main() +{ + std::vector > original_binary_vector { + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 127, 144, 143, 0}, + { 0, 0, 128, 0, 142, 0}, + { 0, 0, 129, 0, 141, 0}, + { 0, 0, 130, 140, 139, 0}, + { 0, 0, 131, 0, 0, 0}, + { 0, 0, 132, 137, 136, 138}, + { 0, 0, 133, 134, 135, 0}}; + std::vector > exp_dil { + { 0,127, 144, 144, 144, 143}, + { 0,128, 144, 144, 144, 143}, + { 0,129, 144, 144, 144, 143}, + { 0,130, 140, 142, 142, 142}, + { 0,131, 140, 141, 141, 141}, + { 0,132, 140, 140, 140, 139}, + { 0,133, 137, 137, 138, 138}, + { 0,133, 137, 137, 138, 138}}; + std::vector > exp_er { + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 132, 0, 0}}; + std::vector > exp_opening { + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 132, 132, 132, 0}, + { 0, 0, 132, 132, 132, 0}}; + std::vector > exp_closing { + { 0,0, 127, 144, 143, 143}, + { 0,0, 127, 144, 143, 143}, + { 0,0, 128, 140, 142, 142}, + { 0,0, 129, 140, 141, 141}, + { 0,0, 130, 140, 139, 139}, + { 0,0, 131, 137, 137, 138}, + { 0,0, 132, 137, 137, 138}, + { 0,0, 133, 137, 137, 138}}; + std::vector > exp_mg { + { 0,127, 144, 144, 144, 143}, + { 0,128, 144, 144, 144, 143}, + { 0,129, 144, 144, 144, 143}, + { 0,130, 140, 142, 142, 142}, + { 0,131, 140, 141, 141, 141}, + { 0,132, 140, 140, 140, 139}, + { 0,133, 137, 137, 138, 138}, + { 0,133, 137, 5, 138, 138}}; + std::vector > exp_top_hat { + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 127, 144, 143, 0}, + { 0, 0, 128, 0, 142, 0}, + { 0, 0, 129, 0, 141, 0}, + { 0, 0, 130, 140, 139, 0}, + { 0, 0, 131, 0, 0, 0}, + { 0, 0, 0, 5, 4, 138}, + { 0, 0, 1, 2, 3, 0}}; + std::vector > exp_black_hat { + { 0,0, 127, 144, 143, 143}, + { 0,0, 0, 0, 0, 143}, + { 0,0, 0, 140, 0, 142}, + { 0,0, 0, 140, 0, 141}, + { 0,0, 0, 0, 0, 139}, + { 0,0, 0, 137, 137, 138}, + { 0,0, 0, 0, 1, 0}, + { 0,0, 0, 3, 2, 138}}; + + gil::gray8_image_t original_img(6,8),obtained_dilation(6,8),expected_dilation(6,8); + gil::gray8_image_t obtained_erosion(6,8),expected_erosion(6,8); + gil::gray8_image_t obtained_opening(6,8),expected_opening(6,8); + gil::gray8_image_t obtained_closing(6,8),expected_closing(6,8); + gil::gray8_image_t obtained_mg(6,8),expected_mg(6,8); + gil::gray8_image_t obtained_top_hat(6,8),expected_top_hat(6,8); + gil::gray8_image_t obtained_black_hat(6,8),expected_black_hat(6,8); + + std::vectorker_vec(9,1.0f);//Structuring element + gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); + + pixel_fill(original_binary_vector,original_img); + pixel_fill(exp_dil,expected_dilation); + pixel_fill(exp_er,expected_erosion); + pixel_fill(exp_opening,expected_opening); + pixel_fill(exp_closing,expected_closing); + pixel_fill(exp_mg,expected_mg); + pixel_fill(exp_top_hat,expected_top_hat); + pixel_fill(exp_black_hat,expected_black_hat); + + gil::dilate(view(original_img),view(obtained_dilation),ker_mat,1); + gil::erode(view(original_img),view(obtained_erosion),ker_mat,1); + gil::opening(view(original_img),view(obtained_opening),ker_mat); + gil::closing(view(original_img),view(obtained_closing),ker_mat); + gil::morphological_gradient(view(original_img),view(obtained_mg),ker_mat); + gil::top_hat(view(original_img),view(obtained_top_hat),ker_mat); + gil::black_hat(view(original_img),view(obtained_black_hat),ker_mat); + + BOOST_TEST(gil::equal_pixels(gil::view(obtained_dilation), gil::view(expected_dilation))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_erosion), gil::view(expected_erosion))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_opening), gil::view(expected_opening))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_closing), gil::view(expected_closing))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_mg), gil::view(expected_mg))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_top_hat), gil::view(expected_top_hat))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_black_hat), gil::view(expected_black_hat))); + return boost::report_errors(); +} \ No newline at end of file From defef606738f67f6198450523533055f403823d7 Mon Sep 17 00:00:00 2001 From: meshtag Date: Fri, 22 Jan 2021 09:56:41 +0530 Subject: [PATCH 08/25] Added command line control --- example/morphology.cpp | 130 ++++++++++++++++++++++++++++++++--------- 1 file changed, 102 insertions(+), 28 deletions(-) diff --git a/example/morphology.cpp b/example/morphology.cpp index f711fc7eb9..3afc6c7d3e 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -9,50 +9,124 @@ #include #include #include - +#include +#include +#include //Default structuring element is SE = [1,1,1] // |1,1,1| // [1,1,1] //SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the //image to be convolved. The structuring element can be easily changed by the user. -int main() +int main(int argc,char **argv) { + std::mapoperations; + if(argc < 4 || argc > 11) + { + std::cout<<"Wrong format of command line arguments.\n"; + std::cout<<"Correct format is " + " " + " \n"; + //User has to enter atleast one operation and they can enter maximum 8 operations + //considering binary conversion to be an operation.Output_image_template argument is the + //common component which will be added in all output images followed by a hyphen and the + //operation name. + //Example : + //./example_morphology original.png out black_hat top_hat morphological_gradient dilation + // erosion opening closing + //Order of arguments entered will not matter with the exception of binary operation used for + //binary morphological operations.If binary is entered through the command line, + //it will always be the first operation to be applied. + return -1; + } + else + { + for(int i=3;iker_vec(9,1.0f);//Structuring element detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); gray8_image_t img_out_dilation(img.dimensions()),img_out_erosion(img.dimensions()),img_out_opening(img.dimensions()); gray8_image_t img_out_closing(img.dimensions()),img_out_mg(img.dimensions()),img_out_top_hat(img.dimensions()); gray8_image_t img_out_black_hat(img.dimensions()); - //dilate(input_image_view,structuring_element,iterations) - dilate(view(img),view(img_out_dilation),ker_mat,1); - //erode(input_image_view,structuring_element,iterations) - erode(view(img),view(img_out_erosion),ker_mat,1); - //opening(input_image_view,structuring_element) - opening(view(img),view(img_out_opening),ker_mat); - //closing(input_image_view,structuring_element) - closing(view(img),view(img_out_closing),ker_mat); - //morphological_gradient(input_image_view,structuring_element) - morphological_gradient(view(img),view(img_out_mg),ker_mat); - //top_hat(input_image_view,structuring_element) - top_hat(view(img),view(img_out_top_hat),ker_mat); - //black_hat(input_image_view,structuring_element) - black_hat(view(img),view(img_out_black_hat),ker_mat); - //Saving results of above morphological transformations. - write_view("out-morphological-example-dilation.png", view(img_out_dilation), png_tag{}); - write_view("out-morphological-example-erosion.png", view(img_out_erosion), png_tag{}); - write_view("out-morphological-example-opening.png", view(img_out_opening), png_tag{}); - write_view("out-morphological-example-closing.png", view(img_out_closing), png_tag{}); - write_view("out-morphological-example-morphological_gradient.png", view(img_out_mg), png_tag{}); - write_view("out-morphological-example-top_hat.png", view(img_out_top_hat), png_tag{}); - write_view("out-morphological-example-black_hat.png", view(img_out_black_hat), png_tag{}); + if(operations["dilation"]) + { + //dilate(input_image_view,structuring_element,iterations) + dilate(view(img),view(img_out_dilation),ker_mat,1); + std::string name = argv[2]; + name += "-dilation.png"; + write_view( name, view(img_out_dilation), png_tag{}); + } + + if(operations["erosion"]) + { + //erode(input_image_view,structuring_element,iterations) + erode(view(img),view(img_out_erosion),ker_mat,1); + std::string name = argv[2]; + name += "-erosion.png"; + write_view( name, view(img_out_erosion), png_tag{}); + } + + if(operations["opening"]) + { + //opening(input_image_view,structuring_element) + opening(view(img),view(img_out_opening),ker_mat); + std::string name = argv[2]; + name += "-opening.png"; + write_view( name, view(img_out_opening), png_tag{}); + } + + if(operations["closing"]) + { + //closing(input_image_view,structuring_element) + closing(view(img),view(img_out_closing),ker_mat); + std::string name = argv[2]; + name += "-closing.png"; + write_view( name, view(img_out_closing), png_tag{}); + } + + if(operations["morphological_gradient"]) + { + //morphological_gradient(input_image_view,structuring_element) + morphological_gradient(view(img),view(img_out_mg),ker_mat); + std::string name = argv[2]; + name += "-morphological_gradient.png"; + write_view(name, view(img_out_mg), png_tag{}); + } + + if(operations["top_hat"]) + { + //top_hat(input_image_view,structuring_element) + top_hat(view(img),view(img_out_top_hat),ker_mat); + std::string name = argv[2]; + name += "-top_hat.png"; + write_view(name, view(img_out_top_hat), png_tag{}); + } + + if(operations["black_hat"]) + { + //black_hat(input_image_view,structuring_element) + black_hat(view(img),view(img_out_black_hat),ker_mat); + std::string name = argv[2]; + name += "-black_hat.png"; + write_view( name, view(img_out_black_hat), png_tag{}); + } } From 22dee6191babc2b206e0aafacc115fb69f9dd90c Mon Sep 17 00:00:00 2001 From: meshtag Date: Fri, 22 Jan 2021 09:58:55 +0530 Subject: [PATCH 09/25] Added command line control --- example/morphology.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/example/morphology.cpp b/example/morphology.cpp index 3afc6c7d3e..cca54888b7 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -44,8 +44,6 @@ int main(int argc,char **argv) for(int i=3;i Date: Wed, 27 Jan 2021 13:53:41 +0530 Subject: [PATCH 10/25] Rectified some things --- example/morphology.cpp | 65 +++---- .../boost/gil/image_processing/morphology.hpp | 163 ++++++++++-------- test/core/image_processing/morphology.cpp | 26 +++ 3 files changed, 148 insertions(+), 106 deletions(-) diff --git a/example/morphology.cpp b/example/morphology.cpp index cca54888b7..bd662310fd 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -5,52 +5,51 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // - #include #include #include #include #include #include -//Default structuring element is SE = [1,1,1] -// |1,1,1| -// [1,1,1] -//SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the -//image to be convolved. The structuring element can be easily changed by the user. +// Default structuring element is SE = [1,1,1] +// |1,1,1| +// [1,1,1] +// SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the +// image to be convolved. The structuring element can be easily changed by the user. int main(int argc,char **argv) { std::mapoperations; if(argc < 4 || argc > 11) { - std::cout<<"Wrong format of command line arguments.\n"; - std::cout<<"Correct format is " + throw std::invalid_argument("Wrong format of command line arguments.\n" + "Correct format is " " " - " \n"; - //User has to enter atleast one operation and they can enter maximum 8 operations - //considering binary conversion to be an operation.Output_image_template argument is the - //common component which will be added in all output images followed by a hyphen and the - //operation name. - //Example : - //./example_morphology original.png out black_hat top_hat morphological_gradient dilation - // erosion opening closing - //Order of arguments entered will not matter with the exception of binary operation used for - //binary morphological operations.If binary is entered through the command line, - //it will always be the first operation to be applied. + " \n"); + // User has to enter atleast one operation and they can enter maximum 8 operations + // considering binary conversion to be an operation.Output_image_template argument is the + // common component which will be added in all output images followed by a hyphen and the + // operation name. + // Example : + // ./example_morphology original.png out black_hat top_hat morphological_gradient dilation + // erosion opening closing + // Order of arguments entered will not matter with the exception of binary operation used + // for binary morphological operations.If binary is entered through the command line, + // it will always be the first operation to be applied. return -1; } else { for(int i=3;iker_vec(9,1.0f);//Structuring element + std::vectorker_vec(9,1.0f);// Structuring element detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); gray8_image_t img_out_dilation(img.dimensions()),img_out_erosion(img.dimensions()),img_out_opening(img.dimensions()); gray8_image_t img_out_closing(img.dimensions()),img_out_mg(img.dimensions()),img_out_top_hat(img.dimensions()); gray8_image_t img_out_black_hat(img.dimensions()); - + + // Do not pass empty input image views in functions defined below for morphological operations + // to avoid errors. if(operations["dilation"]) { - //dilate(input_image_view,structuring_element,iterations) + // dilate(input_image_view,output_image_view,structuring_element,iterations) dilate(view(img),view(img_out_dilation),ker_mat,1); std::string name = argv[2]; name += "-dilation.png"; @@ -76,7 +77,7 @@ int main(int argc,char **argv) if(operations["erosion"]) { - //erode(input_image_view,structuring_element,iterations) + // erode(input_image_view,output_image_view,structuring_element,iterations) erode(view(img),view(img_out_erosion),ker_mat,1); std::string name = argv[2]; name += "-erosion.png"; @@ -85,7 +86,7 @@ int main(int argc,char **argv) if(operations["opening"]) { - //opening(input_image_view,structuring_element) + // opening(input_image_view,output_image_view,structuring_element) opening(view(img),view(img_out_opening),ker_mat); std::string name = argv[2]; name += "-opening.png"; @@ -94,7 +95,7 @@ int main(int argc,char **argv) if(operations["closing"]) { - //closing(input_image_view,structuring_element) + // closing(input_image_view,output_image_view,structuring_element) closing(view(img),view(img_out_closing),ker_mat); std::string name = argv[2]; name += "-closing.png"; @@ -103,7 +104,7 @@ int main(int argc,char **argv) if(operations["morphological_gradient"]) { - //morphological_gradient(input_image_view,structuring_element) + // morphological_gradient(input_image_view,output_image_view,structuring_element) morphological_gradient(view(img),view(img_out_mg),ker_mat); std::string name = argv[2]; name += "-morphological_gradient.png"; @@ -112,7 +113,7 @@ int main(int argc,char **argv) if(operations["top_hat"]) { - //top_hat(input_image_view,structuring_element) + // top_hat(input_image_view,output_image_view,structuring_element) top_hat(view(img),view(img_out_top_hat),ker_mat); std::string name = argv[2]; name += "-top_hat.png"; @@ -121,7 +122,7 @@ int main(int argc,char **argv) if(operations["black_hat"]) { - //black_hat(input_image_view,structuring_element) + // black_hat(input_image_view,output_image_view,structuring_element) black_hat(view(img),view(img_out_black_hat),ker_mat); std::string name = argv[2]; name += "-black_hat.png"; diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index a46318a0ed..d1a3beda9a 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -8,9 +8,7 @@ #ifndef BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP #define BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP - #include - #include #include #include @@ -21,26 +19,22 @@ namespace boost{ namespace gil{ enum class morphological_operations { - dilate, - erode, - opening, - closing, - morphological_gradient, - top_hat, - black_hat + dilation, + erosion, }; namespace detail{ template -void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel,const int identifier) +void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel, + morphological_operations identifier) { - int flip_ker_row, flip_ker_col, row_boundary, col_boundary; - typename channel_type::type max_overlapped_element,min_overlapped_element; + std::ptrdiff_t flip_ker_row, flip_ker_col, row_boundary, col_boundary; + float product; + typename channel_type::type target_element; for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) { for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) { - max_overlapped_element = (std::numeric_limits::type>::min)(); - min_overlapped_element = (std::numeric_limits::type>::max)(); + target_element = src_view(view_col,view_row); for (std::size_t kernel_row = 0; kernel_row < kernel.size(); ++kernel_row) { flip_ker_row = kernel.size() - 1 - kernel_row; // row index of flipped kernel @@ -57,27 +51,46 @@ void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& if (row_boundary >= 0 && row_boundary < src_view.height() && col_boundary >= 0 && col_boundary < src_view.width()) { - if(src_view(col_boundary, row_boundary) > max_overlapped_element) - max_overlapped_element = src_view(col_boundary, row_boundary); - if(src_view(col_boundary, row_boundary) < min_overlapped_element) - min_overlapped_element = src_view(col_boundary, row_boundary); + // We ensure that we consider only those pixels which are overlapped on a + // non-zero kernel_element as + if(kernel.at(flip_ker_row,flip_ker_col)) + { + product = src_view(col_boundary, row_boundary) * + kernel.at(flip_ker_row, flip_ker_col); + if(identifier == boost::gil::morphological_operations::dilation) + { + if(src_view(col_boundary,row_boundary) > target_element) + target_element = src_view(col_boundary,row_boundary); + } + else if(identifier == boost::gil::morphological_operations::erosion) + { + if(src_view(col_boundary,row_boundary) < target_element) + target_element = src_view(col_boundary,row_boundary); + } + } } } } - if(identifier)//identifier = 1 for dilation - dst_view(view_col, view_row) = max_overlapped_element; - else //identifier = 0 for erosion - dst_view(view_col, view_row) = min_overlapped_element; - } + dst_view(view_col, view_row) = target_element; } } +} + + template -void morph(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_mat,const int identifier) +void morph(SrcView const& src_view, DstView & dst_view,Kernel const& ker_mat, + morphological_operations identifier) { using namespace boost::gil; BOOST_ASSERT(ker_mat.size() != 0 && src_view.dimensions() == dst_view.dimensions()); - gil::gray8_image_t intermediate_img(src_view.dimensions()); + + typedef typename channel_type::type d_channel_t; + typedef typename channel_convert_to_unsigned::type channel_t; + typedef pixel gray_pixel_t; + typedef image src_gray_image; + src_gray_image intermediate_img(src_view.dimensions()); + for (std::size_t i = 0; i < src_view.num_channels(); i++) { morph_impl( @@ -86,79 +99,81 @@ void morph(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_ma ker_mat,identifier ); } - gil::transform_pixels(view(intermediate_img),dst_view,[](const gil::gray8_pixel_t& p){return p[0];}); + copy_pixels(view(intermediate_img),dst_view); } -//This function calculates the difference between pixel values of first image_view and second -//image_view.This function can be used for rgb as well as grayscale images. -template -void difference_impl(SrcView const& src_view, DstView const& dst_view, DiffView const& diff_view) +// This function calculates the difference between pixel values of first image_view and second +// image_view.This function can be used for rgb as well as grayscale images. +template +void difference_impl(SrcView const& src_view1, SrcView const& src_view2, DiffView const& diff_view) { - for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) - for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) - diff_view(view_col, view_row) = src_view(view_col,view_row) - dst_view(view_col,view_row); + for (std::ptrdiff_t view_row = 0; view_row < src_view1.height(); ++view_row) + for (std::ptrdiff_t view_col = 0; view_col < src_view1.width(); ++view_col) + diff_view(view_col, view_row) = src_view1(view_col,view_row) - src_view2(view_col,view_row); } -template -void difference(SrcView const& src_view, DstView const& dst_view , DiffView const& diff_view) +template +void difference(SrcView const& src_view1, SrcView const& src_view2 , DiffView const& diff_view) { - - BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions()); - - for (std::size_t i = 0; i < src_view.num_channels(); i++) + for (std::size_t i = 0; i < src_view1.num_channels(); i++) { difference_impl( - nth_channel_view(src_view, i), - nth_channel_view(dst_view, i), + nth_channel_view(src_view1, i), + nth_channel_view(src_view2, i), nth_channel_view(diff_view, i) ); } } -}//namespace boost::gil::detail +}// namespace boost::gil::detail -// Dilation:Give the maximum overlapped value to the pixel overlapping with the center element of -//structuring element.We can vary the number of times dilation happens by varying the +// Dilation : Give the maximum overlapped value to the pixel overlapping with the center element of +// structuring element.We can vary the number of times dilation happens by varying the // argument 'iterations' in the dilate function. -template -void dilate(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_mat,const int iterations) + +// IntOpview is a name for views which are used for performing intermediate operations used for creating +// the required view. +template +void dilate(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat, + const int iterations) { - boost::gil::transform_pixels(src_view,dst_view,[](const boost::gil::gray8_pixel_t& p){return p[0];}); + copy_pixels(src_view,int_op_view); for(int i=0;i -void erode(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_mat,const int iterations) +// Erosion : Give the minimum overlapped value to the pixel overlapping with the center element of +// structuring element.We can vary the number of times erosion happens by varying the +// argument 'iterations' in the erode function. +template +void erode(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat, + const int iterations) { - boost::gil::transform_pixels(src_view,dst_view,[](const boost::gil::gray8_pixel_t& p){return p[0];}); + copy_pixels(src_view,int_op_view); for(int i=0;i -void opening(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_mat) +// Opening : Opening is just another name of erosion followed by dilation. +// It is useful in removing noise. +template +void opening(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat) { - erode(src_view,dst_view,ker_mat,1); - dilate(dst_view,dst_view,ker_mat,1); + erode(src_view,int_op_view,ker_mat,1); + dilate(int_op_view,int_op_view,ker_mat,1); } -//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. -template -void closing(SrcView const& src_view, DstView const& dst_view,Kernel const& ker_mat) +// 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. +template +void closing(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat) { - dilate(src_view,dst_view,ker_mat,1); - erode(dst_view,dst_view,ker_mat,1); + dilate(src_view,int_op_view,ker_mat,1); + erode(int_op_view,int_op_view,ker_mat,1); } -//Morphological Gradient:It is the difference between dilation and erosion of an image. -//The result will look like the outline of the object. +// Morphological Gradient : It is the difference between dilation and erosion of an image. +// The result will look like the outline of the object. template void morphological_gradient(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) { @@ -169,7 +184,7 @@ void morphological_gradient(SrcView const& src_view, DstView const& dst_view, Ke difference(view(int_dilate),view(int_erode),dst_view); } -//Top Hat:It is the difference between input image and Opening of the image. +// Top Hat : It is the difference between input image and Opening of the image. template void top_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) { @@ -179,7 +194,7 @@ void top_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker difference(src_view,view(int_opening),dst_view); } -//Black Hat:It is the difference between the closing of the input image and input image. +// Black Hat : It is the difference between the closing of the input image and input image. template void black_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) { @@ -189,5 +204,5 @@ void black_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& k difference(view(int_closing), src_view,dst_view); } } -}//namespace boost::gil -#endif //BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP +}// namespace boost::gil +#endif // BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP \ No newline at end of file diff --git a/test/core/image_processing/morphology.cpp b/test/core/image_processing/morphology.cpp index 5e8fc9a601..8e652c918d 100644 --- a/test/core/image_processing/morphology.cpp +++ b/test/core/image_processing/morphology.cpp @@ -12,6 +12,8 @@ namespace gil = boost::gil; +// This function helps us fill pixels of a view given as 2nd argument with elements of the vector +// given as 1st argument. void pixel_fill(std::vector > &original_binary_vector, boost::gil::gray8_image_t &original_img) { for (std::ptrdiff_t view_row = 0; view_row < view(original_img).height(); ++view_row) @@ -97,6 +99,19 @@ int main() { 0,0, 0, 137, 137, 138}, { 0,0, 0, 0, 1, 0}, { 0,0, 0, 3, 2, 138}}; + std::vector > orig_dil_imp{ + { 255, 100, 100, 100}, + { 100, 100, 100, 100}, + { 100, 100, 100, 100} + }; + std::vector > exp_dil_imp{ + { 255, 255, 100, 100}, + { 255, 255, 100, 100}, + { 100, 100, 100, 100} + }; + + // All vectors defined above will be used for creating expected image views which are supposed + // to match the views obtained after applying morphological operations. gil::gray8_image_t original_img(6,8),obtained_dilation(6,8),expected_dilation(6,8); gil::gray8_image_t obtained_erosion(6,8),expected_erosion(6,8); @@ -106,6 +121,8 @@ int main() gil::gray8_image_t obtained_top_hat(6,8),expected_top_hat(6,8); gil::gray8_image_t obtained_black_hat(6,8),expected_black_hat(6,8); + gil::gray8_image_t obtained_imp_dil(4,3),expected_imp_dil(4,3),original_imp_dil(4,3); + std::vectorker_vec(9,1.0f);//Structuring element gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); @@ -118,6 +135,11 @@ int main() pixel_fill(exp_top_hat,expected_top_hat); pixel_fill(exp_black_hat,expected_black_hat); + pixel_fill(orig_dil_imp,original_imp_dil); + pixel_fill(exp_dil_imp,expected_imp_dil); + + // Different morphological operations are applied on the same initial image to obtain results + // of our implementation which are then compared with expected results. gil::dilate(view(original_img),view(obtained_dilation),ker_mat,1); gil::erode(view(original_img),view(obtained_erosion),ker_mat,1); gil::opening(view(original_img),view(obtained_opening),ker_mat); @@ -125,7 +147,9 @@ int main() gil::morphological_gradient(view(original_img),view(obtained_mg),ker_mat); gil::top_hat(view(original_img),view(obtained_top_hat),ker_mat); gil::black_hat(view(original_img),view(obtained_black_hat),ker_mat); + gil::dilate(view(original_imp_dil),view(obtained_imp_dil),ker_mat,1); + // Testing obtained results with expected results. BOOST_TEST(gil::equal_pixels(gil::view(obtained_dilation), gil::view(expected_dilation))); BOOST_TEST(gil::equal_pixels(gil::view(obtained_erosion), gil::view(expected_erosion))); BOOST_TEST(gil::equal_pixels(gil::view(obtained_opening), gil::view(expected_opening))); @@ -133,5 +157,7 @@ int main() BOOST_TEST(gil::equal_pixels(gil::view(obtained_mg), gil::view(expected_mg))); BOOST_TEST(gil::equal_pixels(gil::view(obtained_top_hat), gil::view(expected_top_hat))); BOOST_TEST(gil::equal_pixels(gil::view(obtained_black_hat), gil::view(expected_black_hat))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_imp_dil), gil::view(expected_imp_dil))); + return boost::report_errors(); } \ No newline at end of file From ec6a1359234cfb9dc004bd3e55a827216577ad74 Mon Sep 17 00:00:00 2001 From: meshtag Date: Wed, 27 Jan 2021 14:30:36 +0530 Subject: [PATCH 11/25] Rectified some more things --- include/boost/gil/image_processing/morphology.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index d1a3beda9a..0ef705b538 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -28,7 +28,7 @@ void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& morphological_operations identifier) { std::ptrdiff_t flip_ker_row, flip_ker_col, row_boundary, col_boundary; - float product; + typename channel_type::type product; typename channel_type::type target_element; for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) { @@ -60,12 +60,12 @@ void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& if(identifier == boost::gil::morphological_operations::dilation) { if(src_view(col_boundary,row_boundary) > target_element) - target_element = src_view(col_boundary,row_boundary); + target_element = product; } else if(identifier == boost::gil::morphological_operations::erosion) { if(src_view(col_boundary,row_boundary) < target_element) - target_element = src_view(col_boundary,row_boundary); + target_element = product; } } } From 76886fdc95a3c6b3e7068cab99ab3d77c2d6bf68 Mon Sep 17 00:00:00 2001 From: meshtag Date: Wed, 27 Jan 2021 19:22:43 +0530 Subject: [PATCH 12/25] Improved comments --- example/morphology.cpp | 2 +- .../{original.png => morphology_original.png} | Bin .../boost/gil/image_processing/morphology.hpp | 110 +++++++++++++----- 3 files changed, 79 insertions(+), 33 deletions(-) rename example/{original.png => morphology_original.png} (100%) diff --git a/example/morphology.cpp b/example/morphology.cpp index bd662310fd..676659b274 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -31,7 +31,7 @@ int main(int argc,char **argv) // common component which will be added in all output images followed by a hyphen and the // operation name. // Example : - // ./example_morphology original.png out black_hat top_hat morphological_gradient dilation + // ./example_morphology morphology_original.png out black_hat top_hat morphological_gradient dilation // erosion opening closing // Order of arguments entered will not matter with the exception of binary operation used // for binary morphological operations.If binary is entered through the command line, diff --git a/example/original.png b/example/morphology_original.png similarity index 100% rename from example/original.png rename to example/morphology_original.png diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index 0ef705b538..a515cec284 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -10,8 +10,6 @@ #define BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP #include #include -#include -#include #include namespace gil = boost::gil; @@ -28,7 +26,6 @@ void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& morphological_operations identifier) { std::ptrdiff_t flip_ker_row, flip_ker_col, row_boundary, col_boundary; - typename channel_type::type product; typename channel_type::type target_element; for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) { @@ -55,17 +52,15 @@ void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& // non-zero kernel_element as if(kernel.at(flip_ker_row,flip_ker_col)) { - product = src_view(col_boundary, row_boundary) * - kernel.at(flip_ker_row, flip_ker_col); if(identifier == boost::gil::morphological_operations::dilation) { - if(src_view(col_boundary,row_boundary) > target_element) - target_element = product; + if(src_view(col_boundary, row_boundary) > target_element) + target_element = src_view(col_boundary, row_boundary); } else if(identifier == boost::gil::morphological_operations::erosion) { - if(src_view(col_boundary,row_boundary) < target_element) - target_element = product; + if(src_view(col_boundary, row_boundary) < target_element) + target_element = src_view(col_boundary, row_boundary); } } } @@ -76,8 +71,8 @@ void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& } } - - +// This function is used for modifying pixel values of the input image view according to the type +// type of morphological operation specified by the argument 'identifier'. template void morph(SrcView const& src_view, DstView & dst_view,Kernel const& ker_mat, morphological_operations identifier) @@ -102,8 +97,6 @@ void morph(SrcView const& src_view, DstView & dst_view,Kernel const& ker_mat, copy_pixels(view(intermediate_img),dst_view); } -// This function calculates the difference between pixel values of first image_view and second -// image_view.This function can be used for rgb as well as grayscale images. template void difference_impl(SrcView const& src_view1, SrcView const& src_view2, DiffView const& diff_view) { @@ -112,6 +105,8 @@ void difference_impl(SrcView const& src_view1, SrcView const& src_view2, DiffVie diff_view(view_col, view_row) = src_view1(view_col,view_row) - src_view2(view_col,view_row); } +// This function calculates the difference between pixel values of first image_view and second +// image_view.It can be used for rgb as well as grayscale images. template void difference(SrcView const& src_view1, SrcView const& src_view2 , DiffView const& diff_view) { @@ -126,35 +121,59 @@ void difference(SrcView const& src_view1, SrcView const& src_view2 , DiffView co } }// namespace boost::gil::detail -// Dilation : Give the maximum overlapped value to the pixel overlapping with the center element of -// structuring element.We can vary the number of times dilation happens by varying the -// argument 'iterations' in the dilate function. +/// \addtogroup ImageProcessing +/// @{ + +// IntOpView : View utilized for performing intermediate operations which will contribute in +// creating the resultant view . This will contain final resultant view after dilation is performed. + -// IntOpview is a name for views which are used for performing intermediate operations used for creating -// the required view. +/// \brief Applies morphological dilation on the input image view using given structuring element. +/// It gives the maximum overlapped value to the pixel overlapping with the center element of +/// structuring element. +/// \param src_view - Source/input image view. +/// \param int_op_view - Output image view. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying dilation. +/// \param iterations - Specifies the number of times dilation is to be applied on the input image view. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam IntOptView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template void dilate(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat, - const int iterations) + int iterations) { copy_pixels(src_view,int_op_view); for(int i=0;i void erode(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat, - const int iterations) + int iterations) { copy_pixels(src_view,int_op_view); for(int i=0;i void opening(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat) { @@ -162,9 +181,15 @@ void opening(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& dilate(int_op_view,int_op_view,ker_mat,1); } -// 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. +/// \brief Performs dilation and then erosion on the input image view which is exactly opposite +/// to the opening operation . Closing operation can be utilized for closing small holes inside +/// foreground objects. +/// \param src_view - Source/input image view. +/// \param int_op_view - Output image view. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the closing operation. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam IntOptView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template void closing(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat) { @@ -172,8 +197,15 @@ void closing(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& erode(int_op_view,int_op_view,ker_mat,1); } -// Morphological Gradient : It is the difference between dilation and erosion of an image. -// The result will look like the outline of the object. +/// \brief Calculates the difference between image views generated after applying dilation +/// dilation and erosion on an image . The resultant image will look like the outline of the +/// object(s) present in the image. +/// \param src_view - Source/input image view. +/// \param dst_view - Destination view which will store the final result of morphological gradient operation. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the morphological gradient operation. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam DstView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template void morphological_gradient(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) { @@ -184,7 +216,14 @@ void morphological_gradient(SrcView const& src_view, DstView const& dst_view, Ke difference(view(int_dilate),view(int_erode),dst_view); } -// Top Hat : It is the difference between input image and Opening of the image. +/// \brief Calculates the difference between input image view and the view generated by opening +/// operation on the input image view. +/// \param src_view - Source/input image view. +/// \param dst_view - Destination view which will store the final result of top hat operation. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the top hat operation. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam DstView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template void top_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) { @@ -194,7 +233,13 @@ void top_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker difference(src_view,view(int_opening),dst_view); } -// Black Hat : It is the difference between the closing of the input image and input image. +/// \brief Calculates the difference between closing of the input image and input image. +/// \param src_view - Source/input image view. +/// \param dst_view - Destination view which will store the final result of black hat operation. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the black hat operation. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam DstView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template void black_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) { @@ -204,5 +249,6 @@ void black_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& k difference(view(int_closing), src_view,dst_view); } } +/// @} }// namespace boost::gil #endif // BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP \ No newline at end of file From 7497ed895224da9b4c0c177db82b0f31af8ed673 Mon Sep 17 00:00:00 2001 From: meshtag Date: Wed, 27 Jan 2021 23:05:10 +0530 Subject: [PATCH 13/25] Improved comments --- include/boost/gil/image_processing/morphology.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index a515cec284..ef91368a42 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -125,7 +125,7 @@ void difference(SrcView const& src_view1, SrcView const& src_view2 , DiffView co /// @{ // IntOpView : View utilized for performing intermediate operations which will contribute in -// creating the resultant view . This will contain final resultant view after dilation is performed. +// creating the resultant view . /// \brief Applies morphological dilation on the input image view using given structuring element. @@ -136,7 +136,7 @@ void difference(SrcView const& src_view1, SrcView const& src_view2 , DiffView co /// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying dilation. /// \param iterations - Specifies the number of times dilation is to be applied on the input image view. /// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam IntOptView type of output image, models gil::MutableImageViewConcept. +/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. /// \tparam Kernel type of structuring element. template void dilate(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat, @@ -155,7 +155,7 @@ void dilate(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& /// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying erosion. /// \param iterations - Specifies the number of times erosion is to be applied on the input image view. /// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam IntOptView type of output image, models gil::MutableImageViewConcept. +/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. /// \tparam Kernel type of structuring element. template void erode(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat, @@ -172,7 +172,7 @@ void erode(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& k /// \param int_op_view - Output image view. /// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the opening operation. /// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam IntOptView type of output image, models gil::MutableImageViewConcept. +/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. /// \tparam Kernel type of structuring element. template void opening(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat) @@ -188,7 +188,7 @@ void opening(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& /// \param int_op_view - Output image view. /// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the closing operation. /// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam IntOptView type of output image, models gil::MutableImageViewConcept. +/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. /// \tparam Kernel type of structuring element. template void closing(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat) From 8852996fb884d94bdc2ae7391fcc252142d4d0fa Mon Sep 17 00:00:00 2001 From: meshtag Date: Thu, 28 Jan 2021 20:34:08 +0530 Subject: [PATCH 14/25] Improved doxygen comments and added more test cases --- example/morphology.cpp | 4 +- .../boost/gil/image_processing/morphology.hpp | 43 ++++++++-- test/core/image_processing/morphology.cpp | 84 ++++++++++++------- 3 files changed, 95 insertions(+), 36 deletions(-) diff --git a/example/morphology.cpp b/example/morphology.cpp index 676659b274..9fd86cd669 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -31,8 +31,8 @@ int main(int argc,char **argv) // common component which will be added in all output images followed by a hyphen and the // operation name. // Example : - // ./example_morphology morphology_original.png out black_hat top_hat morphological_gradient dilation - // erosion opening closing + // ./example_morphology morphology_original.png out black_hat top_hat morphological_gradient + // dilation erosion opening closing binary // Order of arguments entered will not matter with the exception of binary operation used // for binary morphological operations.If binary is entered through the command line, // it will always be the first operation to be applied. diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index ef91368a42..2e839355ee 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -21,6 +21,19 @@ namespace boost{ erosion, }; namespace detail{ +/// \addtogroup ImageProcessing +/// @{ + +/// \brief Implements morphological operations at pixel level.This function compares neighbouring +/// pixel values according to the kernel and choose minimum/mamximum neighbouring pixel value and +/// assigns it to the pixel under consideration. +/// \param src_view - Source/Input image view. +/// \param dst_view - View which stores the final result of operations performed by this function. +/// \param kernel - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the required morphological operation. +/// \param identifier - Indicates the type of morphological operation to be applied. +/// \tparam SrcView type of source image. +/// \tparam DstView type of output image. +/// \tparam Kernel type of structuring element. template void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel, morphological_operations identifier) @@ -71,8 +84,15 @@ void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& } } -// This function is used for modifying pixel values of the input image view according to the type -// type of morphological operation specified by the argument 'identifier'. +/// \brief Checks feasibility of the desired operation and passes parameter values to the +/// function morph_impl alongwith individual channel views of the input image. +/// \param src_view - Source/Input image view. +/// \param dst_view - View which stores the final result of operations performed by this function. +/// \param kernel - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the required morphological operation. +/// \param identifier - Indicates the type of morphological operation to be applied. +/// \tparam SrcView type of source image. +/// \tparam DstView type of output image. +/// \tparam Kernel type of structuring element. template void morph(SrcView const& src_view, DstView & dst_view,Kernel const& ker_mat, morphological_operations identifier) @@ -97,6 +117,13 @@ void morph(SrcView const& src_view, DstView & dst_view,Kernel const& ker_mat, copy_pixels(view(intermediate_img),dst_view); } +/// \brief Calculates the difference between pixel values of first image_view and second +/// image_view. +/// \param src_view1 - First parameter for subtraction of views. +/// \param src_view2 - Second parameter for subtraction of views. +/// \param diff_view - View containing result of the subtraction of second view from the first view. +/// \tparam SrcView type of source/Input images used for subtraction. +/// \tparam DiffView type of image view containing the result of subtraction. template void difference_impl(SrcView const& src_view1, SrcView const& src_view2, DiffView const& diff_view) { @@ -105,8 +132,13 @@ void difference_impl(SrcView const& src_view1, SrcView const& src_view2, DiffVie diff_view(view_col, view_row) = src_view1(view_col,view_row) - src_view2(view_col,view_row); } -// This function calculates the difference between pixel values of first image_view and second -// image_view.It can be used for rgb as well as grayscale images. +/// \brief Passes parameter values to the function 'difference_impl' alongwith individual +/// channel views of input images. +/// \param src_view1 - First parameter for subtraction of views. +/// \param src_view2 - Second parameter for subtraction of views. +/// \param diff_view - View containing result of the subtraction of second view from the first view. +/// \tparam SrcView type of source/Input images used for subtraction. +/// \tparam DiffView type of image view containing the result of subtraction. template void difference(SrcView const& src_view1, SrcView const& src_view2 , DiffView const& diff_view) { @@ -121,8 +153,7 @@ void difference(SrcView const& src_view1, SrcView const& src_view2 , DiffView co } }// namespace boost::gil::detail -/// \addtogroup ImageProcessing -/// @{ + // IntOpView : View utilized for performing intermediate operations which will contribute in // creating the resultant view . diff --git a/test/core/image_processing/morphology.cpp b/test/core/image_processing/morphology.cpp index 8e652c918d..7cc0c2d572 100644 --- a/test/core/image_processing/morphology.cpp +++ b/test/core/image_processing/morphology.cpp @@ -36,6 +36,13 @@ int main() { 0, 0, 131, 0, 0, 0}, { 0, 0, 132, 137, 136, 138}, { 0, 0, 133, 134, 135, 0}}; + std::vector > orig_dil_imp{ + { 255, 100, 100, 100}, + { 100, 100, 100, 100}, + { 100, 100, 100, 100} + }; + // All vectors defined below will be used for creating expected image views which are supposed + // to match the views obtained after applying morphological operations. std::vector > exp_dil { { 0,127, 144, 144, 144, 143}, { 0,128, 144, 144, 144, 143}, @@ -45,6 +52,18 @@ int main() { 0,132, 140, 140, 140, 139}, { 0,133, 137, 137, 138, 138}, { 0,133, 137, 137, 138, 138}}; + // Following vector intends to check result of dilation operation when it is applied 2 times on + // the original image. + std::vector > exp_dil_iter2{ + { 128,144, 144, 144, 144, 144}, + { 129,144, 144, 144, 144, 144}, + { 130,144, 144, 144, 144, 144}, + { 131,144, 144, 144, 144, 144}, + { 132,140, 142, 142, 142, 142}, + { 133,140, 141, 141, 141, 141}, + { 133,140, 140, 140, 140, 140}, + { 133,137, 137, 138, 138, 138} + }; std::vector > exp_er { { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, @@ -54,6 +73,17 @@ int main() { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 132, 0, 0}}; + // Following vector intends to check result of erosion operation when it is applied 2 times on + // the original image. + std::vector > exp_er_iter2{ + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0}}; std::vector > exp_opening { { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, @@ -99,29 +129,22 @@ int main() { 0,0, 0, 137, 137, 138}, { 0,0, 0, 0, 1, 0}, { 0,0, 0, 3, 2, 138}}; - std::vector > orig_dil_imp{ - { 255, 100, 100, 100}, - { 100, 100, 100, 100}, - { 100, 100, 100, 100} - }; std::vector > exp_dil_imp{ { 255, 255, 100, 100}, { 255, 255, 100, 100}, { 100, 100, 100, 100} }; - // All vectors defined above will be used for creating expected image views which are supposed - // to match the views obtained after applying morphological operations. - - gil::gray8_image_t original_img(6,8),obtained_dilation(6,8),expected_dilation(6,8); - gil::gray8_image_t obtained_erosion(6,8),expected_erosion(6,8); - gil::gray8_image_t obtained_opening(6,8),expected_opening(6,8); - gil::gray8_image_t obtained_closing(6,8),expected_closing(6,8); - gil::gray8_image_t obtained_mg(6,8),expected_mg(6,8); - gil::gray8_image_t obtained_top_hat(6,8),expected_top_hat(6,8); - gil::gray8_image_t obtained_black_hat(6,8),expected_black_hat(6,8); - - gil::gray8_image_t obtained_imp_dil(4,3),expected_imp_dil(4,3),original_imp_dil(4,3); + gil::gray8_image_t original_img(6,8), obtained_dilation(6,8), expected_dilation(6,8); + gil::gray8_image_t obtained_erosion(6,8), expected_erosion(6,8); + gil::gray8_image_t obtained_opening(6,8), expected_opening(6,8); + gil::gray8_image_t obtained_closing(6,8), expected_closing(6,8); + gil::gray8_image_t obtained_mg(6,8), expected_mg(6,8); + gil::gray8_image_t obtained_top_hat(6,8), expected_top_hat(6,8); + gil::gray8_image_t obtained_black_hat(6,8), expected_black_hat(6,8); + gil::gray8_image_t obtained_dil_iter2(6,8), expected_dil_iter2(6,8); + gil::gray8_image_t obtained_er_iter2(6,8), expected_er_iter2(6,8); + gil::gray8_image_t obtained_imp_dil(4,3), expected_imp_dil(4,3), original_imp_dil(4,3); std::vectorker_vec(9,1.0f);//Structuring element gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); @@ -134,21 +157,24 @@ int main() pixel_fill(exp_mg,expected_mg); pixel_fill(exp_top_hat,expected_top_hat); pixel_fill(exp_black_hat,expected_black_hat); - + pixel_fill(exp_dil_iter2,expected_dil_iter2); pixel_fill(orig_dil_imp,original_imp_dil); pixel_fill(exp_dil_imp,expected_imp_dil); + pixel_fill(exp_er_iter2,expected_er_iter2); // Different morphological operations are applied on the same initial image to obtain results // of our implementation which are then compared with expected results. - gil::dilate(view(original_img),view(obtained_dilation),ker_mat,1); - gil::erode(view(original_img),view(obtained_erosion),ker_mat,1); - gil::opening(view(original_img),view(obtained_opening),ker_mat); - gil::closing(view(original_img),view(obtained_closing),ker_mat); - gil::morphological_gradient(view(original_img),view(obtained_mg),ker_mat); - gil::top_hat(view(original_img),view(obtained_top_hat),ker_mat); - gil::black_hat(view(original_img),view(obtained_black_hat),ker_mat); - gil::dilate(view(original_imp_dil),view(obtained_imp_dil),ker_mat,1); - + gil::dilate(view(original_img), view(obtained_dilation),ker_mat,1); + gil::erode(view(original_img), view(obtained_erosion),ker_mat,1); + gil::opening(view(original_img), view(obtained_opening),ker_mat); + gil::closing(view(original_img), view(obtained_closing),ker_mat); + gil::morphological_gradient(view(original_img), view(obtained_mg),ker_mat); + gil::top_hat(view(original_img), view(obtained_top_hat),ker_mat); + gil::black_hat(view(original_img), view(obtained_black_hat),ker_mat); + gil::dilate(view(original_imp_dil), view(obtained_imp_dil),ker_mat,1); + gil::dilate(view(original_img), view(obtained_dil_iter2),ker_mat,2); + gil::erode(view(original_img), view(obtained_er_iter2), ker_mat, 2); + // Testing obtained results with expected results. BOOST_TEST(gil::equal_pixels(gil::view(obtained_dilation), gil::view(expected_dilation))); BOOST_TEST(gil::equal_pixels(gil::view(obtained_erosion), gil::view(expected_erosion))); @@ -158,6 +184,8 @@ int main() BOOST_TEST(gil::equal_pixels(gil::view(obtained_top_hat), gil::view(expected_top_hat))); BOOST_TEST(gil::equal_pixels(gil::view(obtained_black_hat), gil::view(expected_black_hat))); BOOST_TEST(gil::equal_pixels(gil::view(obtained_imp_dil), gil::view(expected_imp_dil))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_dil_iter2), gil::view(expected_dil_iter2))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_er_iter2), gil::view(expected_er_iter2))); return boost::report_errors(); -} \ No newline at end of file +} From b4045ff1415c55c51da5eb20d3445c0476fd2eb4 Mon Sep 17 00:00:00 2001 From: meshtag Date: Fri, 29 Jan 2021 16:11:04 +0530 Subject: [PATCH 15/25] Improved compatibility for builds and rectifying whitespace use --- example/Jamfile | 1 + example/morphology.cpp | 60 +++++----- include/boost/gil.hpp | 1 + .../boost/gil/image_processing/morphology.hpp | 72 ++++++------ test/core/image_processing/CMakeLists.txt | 4 +- test/core/image_processing/Jamfile | 1 + test/core/image_processing/morphology.cpp | 106 +++++++++--------- 7 files changed, 123 insertions(+), 122 deletions(-) diff --git a/example/Jamfile b/example/Jamfile index 48b9e51aef..df17d57c42 100644 --- a/example/Jamfile +++ b/example/Jamfile @@ -30,6 +30,7 @@ local sources = histogram.cpp interleaved_ptr.cpp mandelbrot.cpp + morphology.cpp packed_pixel.cpp resize.cpp sobel_scharr.cpp diff --git a/example/morphology.cpp b/example/morphology.cpp index 9fd86cd669..58ea5c44a3 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -6,20 +6,21 @@ // http://www.boost.org/LICENSE_1_0.txt) // #include -#include +#include #include -#include -#include -#include +#include +#include +#include + // Default structuring element is SE = [1,1,1] // |1,1,1| // [1,1,1] // SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the // image to be convolved. The structuring element can be easily changed by the user. - -int main(int argc,char **argv) +namespace gil = boost::gil; +int main(int argc, char **argv) { - std::mapoperations; + std::map operations; if(argc < 4 || argc > 11) { throw std::invalid_argument("Wrong format of command line arguments.\n" @@ -43,9 +44,8 @@ int main(int argc,char **argv) for(int i=3;iker_vec(9,1.0f);// Structuring element - detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); - gray8_image_t img_out_dilation(img.dimensions()),img_out_erosion(img.dimensions()),img_out_opening(img.dimensions()); - gray8_image_t img_out_closing(img.dimensions()),img_out_mg(img.dimensions()),img_out_top_hat(img.dimensions()); - gray8_image_t img_out_black_hat(img.dimensions()); + std::vector ker_vec(9, 1.0f);// Structuring element + gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); + gil::gray8_image_t img_out_dilation(img.dimensions()), img_out_erosion(img.dimensions()), img_out_opening(img.dimensions()); + gil::gray8_image_t img_out_closing(img.dimensions()), img_out_mg(img.dimensions()), img_out_top_hat(img.dimensions()); + gil::gray8_image_t img_out_black_hat(img.dimensions()); // Do not pass empty input image views in functions defined below for morphological operations // to avoid errors. if(operations["dilation"]) { // dilate(input_image_view,output_image_view,structuring_element,iterations) - dilate(view(img),view(img_out_dilation),ker_mat,1); + dilate(view(img), view(img_out_dilation), ker_mat, 1); std::string name = argv[2]; name += "-dilation.png"; - write_view( name, view(img_out_dilation), png_tag{}); + gil::write_view( name, view(img_out_dilation), gil::png_tag{}); } if(operations["erosion"]) { // erode(input_image_view,output_image_view,structuring_element,iterations) - erode(view(img),view(img_out_erosion),ker_mat,1); + erode(view(img), view(img_out_erosion), ker_mat, 1); std::string name = argv[2]; name += "-erosion.png"; - write_view( name, view(img_out_erosion), png_tag{}); + gil::write_view( name, view(img_out_erosion), gil::png_tag{}); } if(operations["opening"]) { // opening(input_image_view,output_image_view,structuring_element) - opening(view(img),view(img_out_opening),ker_mat); + opening(view(img), view(img_out_opening), ker_mat); std::string name = argv[2]; name += "-opening.png"; - write_view( name, view(img_out_opening), png_tag{}); + gil::write_view( name, view(img_out_opening), gil::png_tag{}); } if(operations["closing"]) { // closing(input_image_view,output_image_view,structuring_element) - closing(view(img),view(img_out_closing),ker_mat); + closing(view(img), view(img_out_closing), ker_mat); std::string name = argv[2]; name += "-closing.png"; - write_view( name, view(img_out_closing), png_tag{}); + gil::write_view( name, view(img_out_closing), gil::png_tag{}); } if(operations["morphological_gradient"]) { // morphological_gradient(input_image_view,output_image_view,structuring_element) - morphological_gradient(view(img),view(img_out_mg),ker_mat); + morphological_gradient(view(img), view(img_out_mg), ker_mat); std::string name = argv[2]; name += "-morphological_gradient.png"; - write_view(name, view(img_out_mg), png_tag{}); + gil::write_view(name, view(img_out_mg), gil::png_tag{}); } if(operations["top_hat"]) { // top_hat(input_image_view,output_image_view,structuring_element) - top_hat(view(img),view(img_out_top_hat),ker_mat); + top_hat(view(img), view(img_out_top_hat), ker_mat); std::string name = argv[2]; name += "-top_hat.png"; - write_view(name, view(img_out_top_hat), png_tag{}); + gil::write_view(name, view(img_out_top_hat), gil::png_tag{}); } if(operations["black_hat"]) { // black_hat(input_image_view,output_image_view,structuring_element) - black_hat(view(img),view(img_out_black_hat),ker_mat); + black_hat(view(img), view(img_out_black_hat), ker_mat); std::string name = argv[2]; name += "-black_hat.png"; - write_view( name, view(img_out_black_hat), png_tag{}); + gil::write_view( name, view(img_out_black_hat), gil::png_tag{}); } } diff --git a/include/boost/gil.hpp b/include/boost/gil.hpp index 797b1e6006..a9d63d0d87 100644 --- a/include/boost/gil.hpp +++ b/include/boost/gil.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index 2e839355ee..f53985471b 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -12,14 +12,13 @@ #include #include -namespace gil = boost::gil; namespace boost{ namespace gil{ - enum class morphological_operations - { - dilation, - erosion, - }; +enum class morphological_operation +{ + dilation, + erosion, +}; namespace detail{ /// \addtogroup ImageProcessing /// @{ @@ -36,7 +35,7 @@ namespace detail{ /// \tparam Kernel type of structuring element. template void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel, - morphological_operations identifier) + morphological_operation identifier) { std::ptrdiff_t flip_ker_row, flip_ker_col, row_boundary, col_boundary; typename channel_type::type target_element; @@ -63,14 +62,14 @@ void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& { // We ensure that we consider only those pixels which are overlapped on a // non-zero kernel_element as - if(kernel.at(flip_ker_row,flip_ker_col)) + if(kernel.at(flip_ker_row, flip_ker_col)) { - if(identifier == boost::gil::morphological_operations::dilation) + if(identifier == morphological_operation::dilation) { if(src_view(col_boundary, row_boundary) > target_element) target_element = src_view(col_boundary, row_boundary); } - else if(identifier == boost::gil::morphological_operations::erosion) + else if(identifier == morphological_operation::erosion) { if(src_view(col_boundary, row_boundary) < target_element) target_element = src_view(col_boundary, row_boundary); @@ -95,15 +94,14 @@ void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& /// \tparam Kernel type of structuring element. template void morph(SrcView const& src_view, DstView & dst_view,Kernel const& ker_mat, - morphological_operations identifier) + morphological_operation identifier) { - using namespace boost::gil; BOOST_ASSERT(ker_mat.size() != 0 && src_view.dimensions() == dst_view.dimensions()); - typedef typename channel_type::type d_channel_t; - typedef typename channel_convert_to_unsigned::type channel_t; - typedef pixel gray_pixel_t; - typedef image src_gray_image; + using d_channel_t = typename channel_type::type ; + using channel_t = typename channel_convert_to_unsigned::type ; + using gray_pixel_t = pixel ; + using src_gray_image = image; src_gray_image intermediate_img(src_view.dimensions()); for (std::size_t i = 0; i < src_view.num_channels(); i++) @@ -114,7 +112,7 @@ void morph(SrcView const& src_view, DstView & dst_view,Kernel const& ker_mat, ker_mat,identifier ); } - copy_pixels(view(intermediate_img),dst_view); + copy_pixels(view(intermediate_img), dst_view); } /// \brief Calculates the difference between pixel values of first image_view and second @@ -129,7 +127,7 @@ void difference_impl(SrcView const& src_view1, SrcView const& src_view2, DiffVie { for (std::ptrdiff_t view_row = 0; view_row < src_view1.height(); ++view_row) for (std::ptrdiff_t view_col = 0; view_col < src_view1.width(); ++view_col) - diff_view(view_col, view_row) = src_view1(view_col,view_row) - src_view2(view_col,view_row); + diff_view(view_col, view_row) = src_view1(view_col, view_row) - src_view2(view_col, view_row); } /// \brief Passes parameter values to the function 'difference_impl' alongwith individual @@ -171,11 +169,11 @@ void difference(SrcView const& src_view1, SrcView const& src_view2 , DiffView co /// \tparam Kernel type of structuring element. template void dilate(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat, - int iterations) + int iterations) { - copy_pixels(src_view,int_op_view); + copy_pixels(src_view, int_op_view); for(int i=0;i void erode(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat, - int iterations) + int iterations) { - copy_pixels(src_view,int_op_view); + copy_pixels(src_view, int_op_view); for(int i=0;i void opening(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat) { - erode(src_view,int_op_view,ker_mat,1); - dilate(int_op_view,int_op_view,ker_mat,1); + erode(src_view, int_op_view, ker_mat, 1); + dilate(int_op_view, int_op_view, ker_mat, 1); } /// \brief Performs dilation and then erosion on the input image view which is exactly opposite @@ -224,8 +222,8 @@ void opening(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& template void closing(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat) { - dilate(src_view,int_op_view,ker_mat,1); - erode(int_op_view,int_op_view,ker_mat,1); + dilate(src_view, int_op_view, ker_mat, 1); + erode(int_op_view, int_op_view, ker_mat, 1); } /// \brief Calculates the difference between image views generated after applying dilation @@ -241,10 +239,10 @@ template void morphological_gradient(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) { using namespace boost::gil; - gray8_image_t int_dilate(src_view.dimensions()),int_erode(src_view.dimensions()); - dilate(src_view,view(int_dilate),ker_mat,1); - erode(src_view,view(int_erode),ker_mat,1); - difference(view(int_dilate),view(int_erode),dst_view); + gray8_image_t int_dilate(src_view.dimensions()), int_erode(src_view.dimensions()); + dilate(src_view, view(int_dilate), ker_mat, 1); + erode(src_view, view(int_erode), ker_mat, 1); + difference(view(int_dilate), view(int_erode), dst_view); } /// \brief Calculates the difference between input image view and the view generated by opening @@ -260,8 +258,8 @@ void top_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker { using namespace boost::gil; gray8_image_t int_opening(src_view.dimensions()); - opening(src_view,view(int_opening),ker_mat); - difference(src_view,view(int_opening),dst_view); + opening(src_view, view(int_opening), ker_mat); + difference(src_view, view(int_opening), dst_view); } /// \brief Calculates the difference between closing of the input image and input image. @@ -276,10 +274,10 @@ void black_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& k { using namespace boost::gil; gray8_image_t int_closing(src_view.dimensions()); - closing(src_view,view(int_closing),ker_mat); - difference(view(int_closing), src_view,dst_view); + closing(src_view, view(int_closing), ker_mat); + difference(view(int_closing), src_view, dst_view); } } /// @} }// namespace boost::gil -#endif // BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP \ No newline at end of file +#endif // BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP diff --git a/test/core/image_processing/CMakeLists.txt b/test/core/image_processing/CMakeLists.txt index ccdb105ea5..1581fd3075 100644 --- a/test/core/image_processing/CMakeLists.txt +++ b/test/core/image_processing/CMakeLists.txt @@ -7,10 +7,10 @@ # http://www.boost.org/LICENSE_1_0.txt) # foreach(_name - morphology threshold_binary threshold_truncate - threshold_otsu) + threshold_otsu + morphology) set(_test t_core_image_processing_${_name}) set(_target test_core_image_processing_${_name}) diff --git a/test/core/image_processing/Jamfile b/test/core/image_processing/Jamfile index a67c4d9f21..acd74d08f2 100644 --- a/test/core/image_processing/Jamfile +++ b/test/core/image_processing/Jamfile @@ -22,3 +22,4 @@ run median_filter.cpp ; run anisotropic_diffusion.cpp ; run hough_line_transform.cpp ; run hough_circle_transform.cpp ; +run morphology.cpp ; diff --git a/test/core/image_processing/morphology.cpp b/test/core/image_processing/morphology.cpp index 7cc0c2d572..63a4352047 100644 --- a/test/core/image_processing/morphology.cpp +++ b/test/core/image_processing/morphology.cpp @@ -14,7 +14,7 @@ namespace gil = boost::gil; // This function helps us fill pixels of a view given as 2nd argument with elements of the vector // given as 1st argument. -void pixel_fill(std::vector > &original_binary_vector, boost::gil::gray8_image_t &original_img) +void pixel_fill(std::vector>& original_binary_vector, boost::gil::gray8_image_t& original_img) { for (std::ptrdiff_t view_row = 0; view_row < view(original_img).height(); ++view_row) { @@ -27,7 +27,7 @@ void pixel_fill(std::vector > &original_binary_vector, boost::g int main() { - std::vector > original_binary_vector { + std::vector> original_binary_vector { { 0, 0, 0, 0, 0, 0}, { 0, 0, 127, 144, 143, 0}, { 0, 0, 128, 0, 142, 0}, @@ -36,35 +36,35 @@ int main() { 0, 0, 131, 0, 0, 0}, { 0, 0, 132, 137, 136, 138}, { 0, 0, 133, 134, 135, 0}}; - std::vector > orig_dil_imp{ + std::vector> orig_dil_imp{ { 255, 100, 100, 100}, { 100, 100, 100, 100}, { 100, 100, 100, 100} }; // All vectors defined below will be used for creating expected image views which are supposed // to match the views obtained after applying morphological operations. - std::vector > exp_dil { - { 0,127, 144, 144, 144, 143}, - { 0,128, 144, 144, 144, 143}, - { 0,129, 144, 144, 144, 143}, - { 0,130, 140, 142, 142, 142}, - { 0,131, 140, 141, 141, 141}, - { 0,132, 140, 140, 140, 139}, - { 0,133, 137, 137, 138, 138}, - { 0,133, 137, 137, 138, 138}}; + std::vector> exp_dil { + { 0, 127, 144, 144, 144, 143}, + { 0, 128, 144, 144, 144, 143}, + { 0, 129, 144, 144, 144, 143}, + { 0, 130, 140, 142, 142, 142}, + { 0, 131, 140, 141, 141, 141}, + { 0, 132, 140, 140, 140, 139}, + { 0, 133, 137, 137, 138, 138}, + { 0, 133, 137, 137, 138, 138}}; // Following vector intends to check result of dilation operation when it is applied 2 times on // the original image. - std::vector > exp_dil_iter2{ - { 128,144, 144, 144, 144, 144}, - { 129,144, 144, 144, 144, 144}, - { 130,144, 144, 144, 144, 144}, - { 131,144, 144, 144, 144, 144}, - { 132,140, 142, 142, 142, 142}, - { 133,140, 141, 141, 141, 141}, - { 133,140, 140, 140, 140, 140}, - { 133,137, 137, 138, 138, 138} + std::vector> exp_dil_iter2{ + { 128, 144, 144, 144, 144, 144}, + { 129, 144, 144, 144, 144, 144}, + { 130, 144, 144, 144, 144, 144}, + { 131, 144, 144, 144, 144, 144}, + { 132, 140, 142, 142, 142, 142}, + { 133, 140, 141, 141, 141, 141}, + { 133, 140, 140, 140, 140, 140}, + { 133, 137, 137, 138, 138, 138} }; - std::vector > exp_er { + std::vector> exp_er { { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, @@ -75,7 +75,7 @@ int main() { 0, 0, 0, 132, 0, 0}}; // Following vector intends to check result of erosion operation when it is applied 2 times on // the original image. - std::vector > exp_er_iter2{ + std::vector> exp_er_iter2{ { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, @@ -84,7 +84,7 @@ int main() { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}}; - std::vector > exp_opening { + std::vector> exp_opening { { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0}, @@ -93,25 +93,25 @@ int main() { 0, 0, 0, 0, 0, 0}, { 0, 0, 132, 132, 132, 0}, { 0, 0, 132, 132, 132, 0}}; - std::vector > exp_closing { - { 0,0, 127, 144, 143, 143}, - { 0,0, 127, 144, 143, 143}, - { 0,0, 128, 140, 142, 142}, - { 0,0, 129, 140, 141, 141}, - { 0,0, 130, 140, 139, 139}, - { 0,0, 131, 137, 137, 138}, - { 0,0, 132, 137, 137, 138}, - { 0,0, 133, 137, 137, 138}}; - std::vector > exp_mg { - { 0,127, 144, 144, 144, 143}, - { 0,128, 144, 144, 144, 143}, - { 0,129, 144, 144, 144, 143}, - { 0,130, 140, 142, 142, 142}, - { 0,131, 140, 141, 141, 141}, - { 0,132, 140, 140, 140, 139}, - { 0,133, 137, 137, 138, 138}, - { 0,133, 137, 5, 138, 138}}; - std::vector > exp_top_hat { + std::vector> exp_closing { + { 0, 0, 127, 144, 143, 143}, + { 0, 0, 127, 144, 143, 143}, + { 0, 0, 128, 140, 142, 142}, + { 0, 0, 129, 140, 141, 141}, + { 0, 0, 130, 140, 139, 139}, + { 0, 0, 131, 137, 137, 138}, + { 0, 0, 132, 137, 137, 138}, + { 0, 0, 133, 137, 137, 138}}; + std::vector> exp_mg { + { 0, 127, 144, 144, 144, 143}, + { 0, 128, 144, 144, 144, 143}, + { 0, 129, 144, 144, 144, 143}, + { 0, 130, 140, 142, 142, 142}, + { 0, 131, 140, 141, 141, 141}, + { 0, 132, 140, 140, 140, 139}, + { 0, 133, 137, 137, 138, 138}, + { 0, 133, 137, 5, 138, 138}}; + std::vector> exp_top_hat { { 0, 0, 0, 0, 0, 0}, { 0, 0, 127, 144, 143, 0}, { 0, 0, 128, 0, 142, 0}, @@ -120,16 +120,16 @@ int main() { 0, 0, 131, 0, 0, 0}, { 0, 0, 0, 5, 4, 138}, { 0, 0, 1, 2, 3, 0}}; - std::vector > exp_black_hat { - { 0,0, 127, 144, 143, 143}, - { 0,0, 0, 0, 0, 143}, - { 0,0, 0, 140, 0, 142}, - { 0,0, 0, 140, 0, 141}, - { 0,0, 0, 0, 0, 139}, - { 0,0, 0, 137, 137, 138}, - { 0,0, 0, 0, 1, 0}, - { 0,0, 0, 3, 2, 138}}; - std::vector > exp_dil_imp{ + std::vector> exp_black_hat { + { 0, 0, 127, 144, 143, 143}, + { 0, 0, 0, 0, 0, 143}, + { 0, 0, 0, 140, 0, 142}, + { 0, 0, 0, 140, 0, 141}, + { 0, 0, 0, 0, 0, 139}, + { 0, 0, 0, 137, 137, 138}, + { 0, 0, 0, 0, 1, 0}, + { 0, 0, 0, 3, 2, 138}}; + std::vector> exp_dil_imp{ { 255, 255, 100, 100}, { 255, 255, 100, 100}, { 100, 100, 100, 100} From 8769f91d1d9b62f4e53cef1640e9076486f8a737 Mon Sep 17 00:00:00 2001 From: meshtag Date: Fri, 29 Jan 2021 16:14:19 +0530 Subject: [PATCH 16/25] Minor improvement in comments --- include/boost/gil/image_processing/morphology.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index f53985471b..a59a9f3e4f 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -191,7 +191,7 @@ void erode(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& k int iterations) { copy_pixels(src_view, int_op_view); - for(int i=0;i Date: Fri, 29 Jan 2021 19:18:59 +0530 Subject: [PATCH 17/25] Did clang formatting --- example/morphology.cpp | 214 +++++---- .../boost/gil/image_processing/morphology.hpp | 426 +++++++++--------- test/core/image_processing/morphology.cpp | 300 ++++++------ 3 files changed, 442 insertions(+), 498 deletions(-) diff --git a/example/morphology.cpp b/example/morphology.cpp index 58ea5c44a3..1905ef8ee8 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -5,127 +5,121 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // -#include #include -#include +#include #include #include #include +#include // Default structuring element is SE = [1,1,1] // |1,1,1| // [1,1,1] -// SE(1,1)(center pixel) is the one which coincides with the currently considered pixel of the -// image to be convolved. The structuring element can be easily changed by the user. +// SE(1,1)(center pixel) is the one which coincides with the currently +// considered pixel of the image to be convolved. The structuring element can be +// easily changed by the user. namespace gil = boost::gil; -int main(int argc, char **argv) -{ - std::map operations; - if(argc < 4 || argc > 11) - { - throw std::invalid_argument("Wrong format of command line arguments.\n" +int main(int argc, char **argv) { + std::map operations; + if (argc < 4 || argc > 11) { + throw std::invalid_argument( + "Wrong format of command line arguments.\n" "Correct format is " - " " + " " + "" " \n"); - // User has to enter atleast one operation and they can enter maximum 8 operations - // considering binary conversion to be an operation.Output_image_template argument is the - // common component which will be added in all output images followed by a hyphen and the - // operation name. - // Example : - // ./example_morphology morphology_original.png out black_hat top_hat morphological_gradient - // dilation erosion opening closing binary - // Order of arguments entered will not matter with the exception of binary operation used - // for binary morphological operations.If binary is entered through the command line, - // it will always be the first operation to be applied. - return -1; - } - else - { - for(int i=3;i ker_vec(9, 1.0f); // Structuring element + gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); + gil::gray8_image_t img_out_dilation(img.dimensions()), + img_out_erosion(img.dimensions()), img_out_opening(img.dimensions()); + gil::gray8_image_t img_out_closing(img.dimensions()), + img_out_mg(img.dimensions()), img_out_top_hat(img.dimensions()); + gil::gray8_image_t img_out_black_hat(img.dimensions()); + + // Do not pass empty input image views in functions defined below for + // morphological operations to avoid errors. + if (operations["dilation"]) { + // dilate(input_image_view,output_image_view,structuring_element,iterations) + dilate(view(img), view(img_out_dilation), ker_mat, 1); + std::string name = argv[2]; + name += "-dilation.png"; + gil::write_view(name, view(img_out_dilation), gil::png_tag{}); + } + + if (operations["erosion"]) { + // erode(input_image_view,output_image_view,structuring_element,iterations) + erode(view(img), view(img_out_erosion), ker_mat, 1); + std::string name = argv[2]; + name += "-erosion.png"; + gil::write_view(name, view(img_out_erosion), gil::png_tag{}); + } + + if (operations["opening"]) { + // opening(input_image_view,output_image_view,structuring_element) + opening(view(img), view(img_out_opening), ker_mat); + std::string name = argv[2]; + name += "-opening.png"; + gil::write_view(name, view(img_out_opening), gil::png_tag{}); + } + + if (operations["closing"]) { + // closing(input_image_view,output_image_view,structuring_element) + closing(view(img), view(img_out_closing), ker_mat); + std::string name = argv[2]; + name += "-closing.png"; + gil::write_view(name, view(img_out_closing), gil::png_tag{}); + } + + if (operations["morphological_gradient"]) { + // morphological_gradient(input_image_view,output_image_view,structuring_element) + morphological_gradient(view(img), view(img_out_mg), ker_mat); + std::string name = argv[2]; + name += "-morphological_gradient.png"; + gil::write_view(name, view(img_out_mg), gil::png_tag{}); + } - // Image can be converted to a binary format with high value as 255 and low value as 0 - // by using the threshold operator . This can be used for binary morphological operations . - // Convenient threshold for binary conversion may be chosen by the user. - if(operations["binary"]) - { - threshold_binary(view(img), view(img),170, 255); - std::string name = argv[2]; - name += "-binary.png"; - gil::write_view(name, view(img), gil::png_tag{}); - } + if (operations["top_hat"]) { + // top_hat(input_image_view,output_image_view,structuring_element) + top_hat(view(img), view(img_out_top_hat), ker_mat); + std::string name = argv[2]; + name += "-top_hat.png"; + gil::write_view(name, view(img_out_top_hat), gil::png_tag{}); + } - std::vector ker_vec(9, 1.0f);// Structuring element - gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); - gil::gray8_image_t img_out_dilation(img.dimensions()), img_out_erosion(img.dimensions()), img_out_opening(img.dimensions()); - gil::gray8_image_t img_out_closing(img.dimensions()), img_out_mg(img.dimensions()), img_out_top_hat(img.dimensions()); - gil::gray8_image_t img_out_black_hat(img.dimensions()); - - // Do not pass empty input image views in functions defined below for morphological operations - // to avoid errors. - if(operations["dilation"]) - { - // dilate(input_image_view,output_image_view,structuring_element,iterations) - dilate(view(img), view(img_out_dilation), ker_mat, 1); - std::string name = argv[2]; - name += "-dilation.png"; - gil::write_view( name, view(img_out_dilation), gil::png_tag{}); - } - - if(operations["erosion"]) - { - // erode(input_image_view,output_image_view,structuring_element,iterations) - erode(view(img), view(img_out_erosion), ker_mat, 1); - std::string name = argv[2]; - name += "-erosion.png"; - gil::write_view( name, view(img_out_erosion), gil::png_tag{}); - } - - if(operations["opening"]) - { - // opening(input_image_view,output_image_view,structuring_element) - opening(view(img), view(img_out_opening), ker_mat); - std::string name = argv[2]; - name += "-opening.png"; - gil::write_view( name, view(img_out_opening), gil::png_tag{}); - } - - if(operations["closing"]) - { - // closing(input_image_view,output_image_view,structuring_element) - closing(view(img), view(img_out_closing), ker_mat); - std::string name = argv[2]; - name += "-closing.png"; - gil::write_view( name, view(img_out_closing), gil::png_tag{}); - } - - if(operations["morphological_gradient"]) - { - // morphological_gradient(input_image_view,output_image_view,structuring_element) - morphological_gradient(view(img), view(img_out_mg), ker_mat); - std::string name = argv[2]; - name += "-morphological_gradient.png"; - gil::write_view(name, view(img_out_mg), gil::png_tag{}); - } - - if(operations["top_hat"]) - { - // top_hat(input_image_view,output_image_view,structuring_element) - top_hat(view(img), view(img_out_top_hat), ker_mat); - std::string name = argv[2]; - name += "-top_hat.png"; - gil::write_view(name, view(img_out_top_hat), gil::png_tag{}); - } - - if(operations["black_hat"]) - { - // black_hat(input_image_view,output_image_view,structuring_element) - black_hat(view(img), view(img_out_black_hat), ker_mat); - std::string name = argv[2]; - name += "-black_hat.png"; - gil::write_view( name, view(img_out_black_hat), gil::png_tag{}); - } + if (operations["black_hat"]) { + // black_hat(input_image_view,output_image_view,structuring_element) + black_hat(view(img), view(img_out_black_hat), ker_mat); + std::string name = argv[2]; + name += "-black_hat.png"; + gil::write_view(name, view(img_out_black_hat), gil::png_tag{}); + } } diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index a59a9f3e4f..cf6be008c5 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -12,272 +12,260 @@ #include #include -namespace boost{ - namespace gil{ -enum class morphological_operation -{ - dilation, - erosion, +namespace boost { +namespace gil { +enum class morphological_operation { + dilation, + erosion, }; -namespace detail{ +namespace detail { /// \addtogroup ImageProcessing /// @{ -/// \brief Implements morphological operations at pixel level.This function compares neighbouring -/// pixel values according to the kernel and choose minimum/mamximum neighbouring pixel value and -/// assigns it to the pixel under consideration. -/// \param src_view - Source/Input image view. -/// \param dst_view - View which stores the final result of operations performed by this function. -/// \param kernel - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the required morphological operation. -/// \param identifier - Indicates the type of morphological operation to be applied. +/// \brief Implements morphological operations at pixel level.This function +/// compares neighbouring pixel values according to the kernel and choose +/// minimum/mamximum neighbouring pixel value and assigns it to the pixel under +/// consideration. \param src_view - Source/Input image view. \param dst_view - +/// View which stores the final result of operations performed by this function. +/// \param kernel - Kernel matrix/structuring element containing 0's and 1's +/// which will be used for applying the required morphological operation. \param +/// identifier - Indicates the type of morphological operation to be applied. /// \tparam SrcView type of source image. /// \tparam DstView type of output image. /// \tparam Kernel type of structuring element. template -void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel, - morphological_operation identifier) -{ - std::ptrdiff_t flip_ker_row, flip_ker_col, row_boundary, col_boundary; - typename channel_type::type target_element; - for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) - { - for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) - { - target_element = src_view(view_col,view_row); - for (std::size_t kernel_row = 0; kernel_row < kernel.size(); ++kernel_row) - { - flip_ker_row = kernel.size() - 1 - kernel_row; // row index of flipped kernel +void morph_impl(SrcView const &src_view, DstView const &dst_view, + Kernel const &kernel, morphological_operation identifier) { + std::ptrdiff_t flip_ker_row, flip_ker_col, row_boundary, col_boundary; + typename channel_type::type target_element; + for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) { + for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) { + target_element = src_view(view_col, view_row); + for (std::size_t kernel_row = 0; kernel_row < kernel.size(); + ++kernel_row) { + flip_ker_row = + kernel.size() - 1 - kernel_row; // row index of flipped kernel - for (std::size_t kernel_col = 0; kernel_col < kernel.size(); ++kernel_col) - { - flip_ker_col = kernel.size() - 1 - kernel_col; // column index of flipped kernel + for (std::size_t kernel_col = 0; kernel_col < kernel.size(); + ++kernel_col) { + flip_ker_col = + kernel.size() - 1 - kernel_col; // column index of flipped kernel - // index of input signal, used for checking boundary - row_boundary = view_row + (kernel.center_y() - flip_ker_row); - col_boundary = view_col + (kernel.center_x() - flip_ker_col); + // index of input signal, used for checking boundary + row_boundary = view_row + (kernel.center_y() - flip_ker_row); + col_boundary = view_col + (kernel.center_x() - flip_ker_col); - // ignore input samples which are out of bound - if (row_boundary >= 0 && row_boundary < src_view.height() && - col_boundary >= 0 && col_boundary < src_view.width()) - { - // We ensure that we consider only those pixels which are overlapped on a - // non-zero kernel_element as - if(kernel.at(flip_ker_row, flip_ker_col)) - { - if(identifier == morphological_operation::dilation) - { - if(src_view(col_boundary, row_boundary) > target_element) - target_element = src_view(col_boundary, row_boundary); - } - else if(identifier == morphological_operation::erosion) - { - if(src_view(col_boundary, row_boundary) < target_element) - target_element = src_view(col_boundary, row_boundary); - } - } - } - } + // ignore input samples which are out of bound + if (row_boundary >= 0 && row_boundary < src_view.height() && + col_boundary >= 0 && col_boundary < src_view.width()) { + // We ensure that we consider only those pixels which are overlapped + // on a non-zero kernel_element as + if (kernel.at(flip_ker_row, flip_ker_col)) { + if (identifier == morphological_operation::dilation) { + if (src_view(col_boundary, row_boundary) > target_element) + target_element = src_view(col_boundary, row_boundary); + } else if (identifier == morphological_operation::erosion) { + if (src_view(col_boundary, row_boundary) < target_element) + target_element = src_view(col_boundary, row_boundary); + } } - dst_view(view_col, view_row) = target_element; + } } + } + dst_view(view_col, view_row) = target_element; } + } } -/// \brief Checks feasibility of the desired operation and passes parameter values to the -/// function morph_impl alongwith individual channel views of the input image. -/// \param src_view - Source/Input image view. -/// \param dst_view - View which stores the final result of operations performed by this function. -/// \param kernel - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the required morphological operation. -/// \param identifier - Indicates the type of morphological operation to be applied. +/// \brief Checks feasibility of the desired operation and passes parameter +/// values to the function morph_impl alongwith individual channel views of the +/// input image. \param src_view - Source/Input image view. \param dst_view - +/// View which stores the final result of operations performed by this function. +/// \param kernel - Kernel matrix/structuring element containing 0's and 1's +/// which will be used for applying the required morphological operation. \param +/// identifier - Indicates the type of morphological operation to be applied. /// \tparam SrcView type of source image. /// \tparam DstView type of output image. /// \tparam Kernel type of structuring element. -template -void morph(SrcView const& src_view, DstView & dst_view,Kernel const& ker_mat, - morphological_operation identifier) -{ - BOOST_ASSERT(ker_mat.size() != 0 && src_view.dimensions() == dst_view.dimensions()); +template +void morph(SrcView const &src_view, DstView &dst_view, Kernel const &ker_mat, + morphological_operation identifier) { + BOOST_ASSERT(ker_mat.size() != 0 && + src_view.dimensions() == dst_view.dimensions()); - using d_channel_t = typename channel_type::type ; - using channel_t = typename channel_convert_to_unsigned::type ; - using gray_pixel_t = pixel ; - using src_gray_image = image; - src_gray_image intermediate_img(src_view.dimensions()); + using d_channel_t = typename channel_type::type; + using channel_t = typename channel_convert_to_unsigned::type; + using gray_pixel_t = pixel; + using src_gray_image = image; + src_gray_image intermediate_img(src_view.dimensions()); - for (std::size_t i = 0; i < src_view.num_channels(); i++) - { - morph_impl( - nth_channel_view(src_view, i), - nth_channel_view(view(intermediate_img), i), - ker_mat,identifier - ); - } - copy_pixels(view(intermediate_img), dst_view); + for (std::size_t i = 0; i < src_view.num_channels(); i++) { + morph_impl(nth_channel_view(src_view, i), + nth_channel_view(view(intermediate_img), i), ker_mat, + identifier); + } + copy_pixels(view(intermediate_img), dst_view); } -/// \brief Calculates the difference between pixel values of first image_view and second -/// image_view. -/// \param src_view1 - First parameter for subtraction of views. -/// \param src_view2 - Second parameter for subtraction of views. -/// \param diff_view - View containing result of the subtraction of second view from the first view. -/// \tparam SrcView type of source/Input images used for subtraction. -/// \tparam DiffView type of image view containing the result of subtraction. +/// \brief Calculates the difference between pixel values of first image_view +/// and second image_view. \param src_view1 - First parameter for subtraction of +/// views. \param src_view2 - Second parameter for subtraction of views. \param +/// diff_view - View containing result of the subtraction of second view from +/// the first view. \tparam SrcView type of source/Input images used for +/// subtraction. \tparam DiffView type of image view containing the result of +/// subtraction. template -void difference_impl(SrcView const& src_view1, SrcView const& src_view2, DiffView const& diff_view) -{ - for (std::ptrdiff_t view_row = 0; view_row < src_view1.height(); ++view_row) - for (std::ptrdiff_t view_col = 0; view_col < src_view1.width(); ++view_col) - diff_view(view_col, view_row) = src_view1(view_col, view_row) - src_view2(view_col, view_row); +void difference_impl(SrcView const &src_view1, SrcView const &src_view2, + DiffView const &diff_view) { + for (std::ptrdiff_t view_row = 0; view_row < src_view1.height(); ++view_row) + for (std::ptrdiff_t view_col = 0; view_col < src_view1.width(); ++view_col) + diff_view(view_col, view_row) = + src_view1(view_col, view_row) - src_view2(view_col, view_row); } -/// \brief Passes parameter values to the function 'difference_impl' alongwith individual -/// channel views of input images. -/// \param src_view1 - First parameter for subtraction of views. -/// \param src_view2 - Second parameter for subtraction of views. -/// \param diff_view - View containing result of the subtraction of second view from the first view. -/// \tparam SrcView type of source/Input images used for subtraction. -/// \tparam DiffView type of image view containing the result of subtraction. +/// \brief Passes parameter values to the function 'difference_impl' alongwith +/// individual channel views of input images. \param src_view1 - First parameter +/// for subtraction of views. \param src_view2 - Second parameter for +/// subtraction of views. \param diff_view - View containing result of the +/// subtraction of second view from the first view. \tparam SrcView type of +/// source/Input images used for subtraction. \tparam DiffView type of image +/// view containing the result of subtraction. template -void difference(SrcView const& src_view1, SrcView const& src_view2 , DiffView const& diff_view) -{ - for (std::size_t i = 0; i < src_view1.num_channels(); i++) - { - difference_impl( - nth_channel_view(src_view1, i), - nth_channel_view(src_view2, i), - nth_channel_view(diff_view, i) - ); - } +void difference(SrcView const &src_view1, SrcView const &src_view2, + DiffView const &diff_view) { + for (std::size_t i = 0; i < src_view1.num_channels(); i++) { + difference_impl(nth_channel_view(src_view1, i), + nth_channel_view(src_view2, i), + nth_channel_view(diff_view, i)); + } } -}// namespace boost::gil::detail - +} // namespace detail +// IntOpView : View utilized for performing intermediate operations which will +// contribute in creating the resultant view . -// IntOpView : View utilized for performing intermediate operations which will contribute in -// creating the resultant view . - - -/// \brief Applies morphological dilation on the input image view using given structuring element. -/// It gives the maximum overlapped value to the pixel overlapping with the center element of +/// \brief Applies morphological dilation on the input image view using given +/// structuring element. It gives the maximum overlapped value to the pixel +/// overlapping with the center element of structuring element. \param src_view +/// - Source/input image view. \param int_op_view - Output image view. \param +/// ker_mat - Kernel matrix/structuring element containing 0's and 1's which +/// will be used for applying dilation. \param iterations - Specifies the number +/// of times dilation is to be applied on the input image view. \tparam SrcView +/// type of source image, models gil::ImageViewConcept. \tparam IntOpView type +/// of output image, models gil::MutableImageViewConcept. \tparam Kernel type of /// structuring element. -/// \param src_view - Source/input image view. -/// \param int_op_view - Output image view. -/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying dilation. -/// \param iterations - Specifies the number of times dilation is to be applied on the input image view. -/// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. -/// \tparam Kernel type of structuring element. -template -void dilate(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat, - int iterations) -{ - copy_pixels(src_view, int_op_view); - for(int i=0;i +void dilate(SrcView const &src_view, IntOpView const &int_op_view, + Kernel const &ker_mat, int iterations) { + copy_pixels(src_view, int_op_view); + for (int i = 0; i < iterations; ++i) + morph(int_op_view, int_op_view, ker_mat, morphological_operation::dilation); } -/// \brief Applies morphological erosion on the input image view using given structuring element. -/// It gives the minimum overlapped value to the pixel overlapping with the center element of +/// \brief Applies morphological erosion on the input image view using given +/// structuring element. It gives the minimum overlapped value to the pixel +/// overlapping with the center element of structuring element. \param src_view +/// - Source/input image view. \param int_op_view - Output image view. \param +/// ker_mat - Kernel matrix/structuring element containing 0's and 1's which +/// will be used for applying erosion. \param iterations - Specifies the number +/// of times erosion is to be applied on the input image view. \tparam SrcView +/// type of source image, models gil::ImageViewConcept. \tparam IntOpView type +/// of output image, models gil::MutableImageViewConcept. \tparam Kernel type of /// structuring element. -/// \param src_view - Source/input image view. -/// \param int_op_view - Output image view. -/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying erosion. -/// \param iterations - Specifies the number of times erosion is to be applied on the input image view. -/// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. -/// \tparam Kernel type of structuring element. -template -void erode(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat, - int iterations) -{ - copy_pixels(src_view, int_op_view); - for(int i = 0;i < iterations; ++i) - morph(int_op_view, int_op_view,ker_mat, morphological_operation::erosion); +template +void erode(SrcView const &src_view, IntOpView const &int_op_view, + Kernel const &ker_mat, int iterations) { + copy_pixels(src_view, int_op_view); + for (int i = 0; i < iterations; ++i) + morph(int_op_view, int_op_view, ker_mat, morphological_operation::erosion); } -/// \brief Performs erosion and then dilation on the input image view . This operation is utilized -/// for removing noise from images. -/// \param src_view - Source/input image view. -/// \param int_op_view - Output image view. -/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the opening operation. -/// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. -/// \tparam Kernel type of structuring element. -template -void opening(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat) -{ - erode(src_view, int_op_view, ker_mat, 1); - dilate(int_op_view, int_op_view, ker_mat, 1); +/// \brief Performs erosion and then dilation on the input image view . This +/// operation is utilized for removing noise from images. \param src_view - +/// Source/input image view. \param int_op_view - Output image view. \param +/// ker_mat - Kernel matrix/structuring element containing 0's and 1's which +/// will be used for applying the opening operation. \tparam SrcView type of +/// source image, models gil::ImageViewConcept. \tparam IntOpView type of output +/// image, models gil::MutableImageViewConcept. \tparam Kernel type of +/// structuring element. +template +void opening(SrcView const &src_view, IntOpView const &int_op_view, + Kernel const &ker_mat) { + erode(src_view, int_op_view, ker_mat, 1); + dilate(int_op_view, int_op_view, ker_mat, 1); } -/// \brief Performs dilation and then erosion on the input image view which is exactly opposite -/// to the opening operation . Closing operation can be utilized for closing small holes inside -/// foreground objects. -/// \param src_view - Source/input image view. -/// \param int_op_view - Output image view. -/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the closing operation. -/// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. -/// \tparam Kernel type of structuring element. -template -void closing(SrcView const& src_view, IntOpView const& int_op_view,Kernel const& ker_mat) -{ - dilate(src_view, int_op_view, ker_mat, 1); - erode(int_op_view, int_op_view, ker_mat, 1); +/// \brief Performs dilation and then erosion on the input image view which is +/// exactly opposite to the opening operation . Closing operation can be +/// utilized for closing small holes inside foreground objects. \param src_view +/// - Source/input image view. \param int_op_view - Output image view. \param +/// ker_mat - Kernel matrix/structuring element containing 0's and 1's which +/// will be used for applying the closing operation. \tparam SrcView type of +/// source image, models gil::ImageViewConcept. \tparam IntOpView type of output +/// image, models gil::MutableImageViewConcept. \tparam Kernel type of +/// structuring element. +template +void closing(SrcView const &src_view, IntOpView const &int_op_view, + Kernel const &ker_mat) { + dilate(src_view, int_op_view, ker_mat, 1); + erode(int_op_view, int_op_view, ker_mat, 1); } -/// \brief Calculates the difference between image views generated after applying dilation -/// dilation and erosion on an image . The resultant image will look like the outline of the -/// object(s) present in the image. -/// \param src_view - Source/input image view. -/// \param dst_view - Destination view which will store the final result of morphological gradient operation. -/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the morphological gradient operation. -/// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam DstView type of output image, models gil::MutableImageViewConcept. -/// \tparam Kernel type of structuring element. +/// \brief Calculates the difference between image views generated after +/// applying dilation dilation and erosion on an image . The resultant image +/// will look like the outline of the object(s) present in the image. \param +/// src_view - Source/input image view. \param dst_view - Destination view which +/// will store the final result of morphological gradient operation. \param +/// ker_mat - Kernel matrix/structuring element containing 0's and 1's which +/// will be used for applying the morphological gradient operation. \tparam +/// SrcView type of source image, models gil::ImageViewConcept. \tparam DstView +/// type of output image, models gil::MutableImageViewConcept. \tparam Kernel +/// type of structuring element. template -void morphological_gradient(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) -{ - using namespace boost::gil; - gray8_image_t int_dilate(src_view.dimensions()), int_erode(src_view.dimensions()); - dilate(src_view, view(int_dilate), ker_mat, 1); - erode(src_view, view(int_erode), ker_mat, 1); - difference(view(int_dilate), view(int_erode), dst_view); +void morphological_gradient(SrcView const &src_view, DstView const &dst_view, + Kernel const &ker_mat) { + using namespace boost::gil; + gray8_image_t int_dilate(src_view.dimensions()), + int_erode(src_view.dimensions()); + dilate(src_view, view(int_dilate), ker_mat, 1); + erode(src_view, view(int_erode), ker_mat, 1); + difference(view(int_dilate), view(int_erode), dst_view); } -/// \brief Calculates the difference between input image view and the view generated by opening -/// operation on the input image view. -/// \param src_view - Source/input image view. -/// \param dst_view - Destination view which will store the final result of top hat operation. -/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the top hat operation. -/// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam DstView type of output image, models gil::MutableImageViewConcept. -/// \tparam Kernel type of structuring element. +/// \brief Calculates the difference between input image view and the view +/// generated by opening operation on the input image view. \param src_view - +/// Source/input image view. \param dst_view - Destination view which will store +/// the final result of top hat operation. \param ker_mat - Kernel +/// matrix/structuring element containing 0's and 1's which will be used for +/// applying the top hat operation. \tparam SrcView type of source image, models +/// gil::ImageViewConcept. \tparam DstView type of output image, models +/// gil::MutableImageViewConcept. \tparam Kernel type of structuring element. template -void top_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) -{ - using namespace boost::gil; - gray8_image_t int_opening(src_view.dimensions()); - opening(src_view, view(int_opening), ker_mat); - difference(src_view, view(int_opening), dst_view); +void top_hat(SrcView const &src_view, DstView const &dst_view, + Kernel const &ker_mat) { + using namespace boost::gil; + gray8_image_t int_opening(src_view.dimensions()); + opening(src_view, view(int_opening), ker_mat); + difference(src_view, view(int_opening), dst_view); } -/// \brief Calculates the difference between closing of the input image and input image. -/// \param src_view - Source/input image view. -/// \param dst_view - Destination view which will store the final result of black hat operation. -/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for applying the black hat operation. -/// \tparam SrcView type of source image, models gil::ImageViewConcept. -/// \tparam DstView type of output image, models gil::MutableImageViewConcept. -/// \tparam Kernel type of structuring element. +/// \brief Calculates the difference between closing of the input image and +/// input image. \param src_view - Source/input image view. \param dst_view - +/// Destination view which will store the final result of black hat operation. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's +/// which will be used for applying the black hat operation. \tparam SrcView +/// type of source image, models gil::ImageViewConcept. \tparam DstView type of +/// output image, models gil::MutableImageViewConcept. \tparam Kernel type of +/// structuring element. template -void black_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) -{ - using namespace boost::gil; - gray8_image_t int_closing(src_view.dimensions()); - closing(src_view, view(int_closing), ker_mat); - difference(view(int_closing), src_view, dst_view); +void black_hat(SrcView const &src_view, DstView const &dst_view, + Kernel const &ker_mat) { + using namespace boost::gil; + gray8_image_t int_closing(src_view.dimensions()); + closing(src_view, view(int_closing), ker_mat); + difference(view(int_closing), src_view, dst_view); } - } +} // namespace gil /// @} -}// namespace boost::gil +} // namespace boost #endif // BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP diff --git a/test/core/image_processing/morphology.cpp b/test/core/image_processing/morphology.cpp index 63a4352047..2d132e596e 100644 --- a/test/core/image_processing/morphology.cpp +++ b/test/core/image_processing/morphology.cpp @@ -6,186 +6,148 @@ // http://www.boost.org/LICENSE_1_0.txt) // -#include #include +#include #include namespace gil = boost::gil; -// This function helps us fill pixels of a view given as 2nd argument with elements of the vector -// given as 1st argument. -void pixel_fill(std::vector>& original_binary_vector, boost::gil::gray8_image_t& original_img) -{ - for (std::ptrdiff_t view_row = 0; view_row < view(original_img).height(); ++view_row) - { - for (std::ptrdiff_t view_col = 0; view_col < view(original_img).width(); ++view_col) - { - view(original_img)(view_col,view_row) = gil::gray8_pixel_t(original_binary_vector[view_row][view_col]); - } +// This function helps us fill pixels of a view given as 2nd argument with +// elements of the vector given as 1st argument. +void pixel_fill(std::vector> &original_binary_vector, + boost::gil::gray8_image_t &original_img) { + for (std::ptrdiff_t view_row = 0; view_row < view(original_img).height(); + ++view_row) { + for (std::ptrdiff_t view_col = 0; view_col < view(original_img).width(); + ++view_col) { + view(original_img)(view_col, view_row) = + gil::gray8_pixel_t(original_binary_vector[view_row][view_col]); } + } } -int main() -{ - std::vector> original_binary_vector { - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 127, 144, 143, 0}, - { 0, 0, 128, 0, 142, 0}, - { 0, 0, 129, 0, 141, 0}, - { 0, 0, 130, 140, 139, 0}, - { 0, 0, 131, 0, 0, 0}, - { 0, 0, 132, 137, 136, 138}, - { 0, 0, 133, 134, 135, 0}}; - std::vector> orig_dil_imp{ - { 255, 100, 100, 100}, - { 100, 100, 100, 100}, - { 100, 100, 100, 100} - }; - // All vectors defined below will be used for creating expected image views which are supposed - // to match the views obtained after applying morphological operations. - std::vector> exp_dil { - { 0, 127, 144, 144, 144, 143}, - { 0, 128, 144, 144, 144, 143}, - { 0, 129, 144, 144, 144, 143}, - { 0, 130, 140, 142, 142, 142}, - { 0, 131, 140, 141, 141, 141}, - { 0, 132, 140, 140, 140, 139}, - { 0, 133, 137, 137, 138, 138}, - { 0, 133, 137, 137, 138, 138}}; - // Following vector intends to check result of dilation operation when it is applied 2 times on - // the original image. - std::vector> exp_dil_iter2{ - { 128, 144, 144, 144, 144, 144}, - { 129, 144, 144, 144, 144, 144}, - { 130, 144, 144, 144, 144, 144}, - { 131, 144, 144, 144, 144, 144}, - { 132, 140, 142, 142, 142, 142}, - { 133, 140, 141, 141, 141, 141}, - { 133, 140, 140, 140, 140, 140}, - { 133, 137, 137, 138, 138, 138} - }; - std::vector> exp_er { - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 132, 0, 0}}; - // Following vector intends to check result of erosion operation when it is applied 2 times on - // the original image. - std::vector> exp_er_iter2{ - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}}; - std::vector> exp_opening { - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 132, 132, 132, 0}, - { 0, 0, 132, 132, 132, 0}}; - std::vector> exp_closing { - { 0, 0, 127, 144, 143, 143}, - { 0, 0, 127, 144, 143, 143}, - { 0, 0, 128, 140, 142, 142}, - { 0, 0, 129, 140, 141, 141}, - { 0, 0, 130, 140, 139, 139}, - { 0, 0, 131, 137, 137, 138}, - { 0, 0, 132, 137, 137, 138}, - { 0, 0, 133, 137, 137, 138}}; - std::vector> exp_mg { - { 0, 127, 144, 144, 144, 143}, - { 0, 128, 144, 144, 144, 143}, - { 0, 129, 144, 144, 144, 143}, - { 0, 130, 140, 142, 142, 142}, - { 0, 131, 140, 141, 141, 141}, - { 0, 132, 140, 140, 140, 139}, - { 0, 133, 137, 137, 138, 138}, - { 0, 133, 137, 5, 138, 138}}; - std::vector> exp_top_hat { - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 127, 144, 143, 0}, - { 0, 0, 128, 0, 142, 0}, - { 0, 0, 129, 0, 141, 0}, - { 0, 0, 130, 140, 139, 0}, - { 0, 0, 131, 0, 0, 0}, - { 0, 0, 0, 5, 4, 138}, - { 0, 0, 1, 2, 3, 0}}; - std::vector> exp_black_hat { - { 0, 0, 127, 144, 143, 143}, - { 0, 0, 0, 0, 0, 143}, - { 0, 0, 0, 140, 0, 142}, - { 0, 0, 0, 140, 0, 141}, - { 0, 0, 0, 0, 0, 139}, - { 0, 0, 0, 137, 137, 138}, - { 0, 0, 0, 0, 1, 0}, - { 0, 0, 0, 3, 2, 138}}; - std::vector> exp_dil_imp{ - { 255, 255, 100, 100}, - { 255, 255, 100, 100}, - { 100, 100, 100, 100} - }; +int main() { + std::vector> original_binary_vector{ + {0, 0, 0, 0, 0, 0}, {0, 0, 127, 144, 143, 0}, + {0, 0, 128, 0, 142, 0}, {0, 0, 129, 0, 141, 0}, + {0, 0, 130, 140, 139, 0}, {0, 0, 131, 0, 0, 0}, + {0, 0, 132, 137, 136, 138}, {0, 0, 133, 134, 135, 0}}; + std::vector> orig_dil_imp{ + {255, 100, 100, 100}, {100, 100, 100, 100}, {100, 100, 100, 100}}; + // All vectors defined below will be used for creating expected image views + // which are supposed to match the views obtained after applying morphological + // operations. + std::vector> exp_dil{ + {0, 127, 144, 144, 144, 143}, {0, 128, 144, 144, 144, 143}, + {0, 129, 144, 144, 144, 143}, {0, 130, 140, 142, 142, 142}, + {0, 131, 140, 141, 141, 141}, {0, 132, 140, 140, 140, 139}, + {0, 133, 137, 137, 138, 138}, {0, 133, 137, 137, 138, 138}}; + // Following vector intends to check result of dilation operation when it is + // applied 2 times on the original image. + std::vector> exp_dil_iter2{ + {128, 144, 144, 144, 144, 144}, {129, 144, 144, 144, 144, 144}, + {130, 144, 144, 144, 144, 144}, {131, 144, 144, 144, 144, 144}, + {132, 140, 142, 142, 142, 142}, {133, 140, 141, 141, 141, 141}, + {133, 140, 140, 140, 140, 140}, {133, 137, 137, 138, 138, 138}}; + std::vector> exp_er{ + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 132, 0, 0}}; + // Following vector intends to check result of erosion operation when it is + // applied 2 times on the original image. + std::vector> exp_er_iter2{ + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; + std::vector> exp_opening{ + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, + {0, 0, 132, 132, 132, 0}, {0, 0, 132, 132, 132, 0}}; + std::vector> exp_closing{ + {0, 0, 127, 144, 143, 143}, {0, 0, 127, 144, 143, 143}, + {0, 0, 128, 140, 142, 142}, {0, 0, 129, 140, 141, 141}, + {0, 0, 130, 140, 139, 139}, {0, 0, 131, 137, 137, 138}, + {0, 0, 132, 137, 137, 138}, {0, 0, 133, 137, 137, 138}}; + std::vector> exp_mg{ + {0, 127, 144, 144, 144, 143}, {0, 128, 144, 144, 144, 143}, + {0, 129, 144, 144, 144, 143}, {0, 130, 140, 142, 142, 142}, + {0, 131, 140, 141, 141, 141}, {0, 132, 140, 140, 140, 139}, + {0, 133, 137, 137, 138, 138}, {0, 133, 137, 5, 138, 138}}; + std::vector> exp_top_hat{ + {0, 0, 0, 0, 0, 0}, {0, 0, 127, 144, 143, 0}, {0, 0, 128, 0, 142, 0}, + {0, 0, 129, 0, 141, 0}, {0, 0, 130, 140, 139, 0}, {0, 0, 131, 0, 0, 0}, + {0, 0, 0, 5, 4, 138}, {0, 0, 1, 2, 3, 0}}; + std::vector> exp_black_hat{ + {0, 0, 127, 144, 143, 143}, {0, 0, 0, 0, 0, 143}, + {0, 0, 0, 140, 0, 142}, {0, 0, 0, 140, 0, 141}, + {0, 0, 0, 0, 0, 139}, {0, 0, 0, 137, 137, 138}, + {0, 0, 0, 0, 1, 0}, {0, 0, 0, 3, 2, 138}}; + std::vector> exp_dil_imp{ + {255, 255, 100, 100}, {255, 255, 100, 100}, {100, 100, 100, 100}}; + + gil::gray8_image_t original_img(6, 8), obtained_dilation(6, 8), + expected_dilation(6, 8); + gil::gray8_image_t obtained_erosion(6, 8), expected_erosion(6, 8); + gil::gray8_image_t obtained_opening(6, 8), expected_opening(6, 8); + gil::gray8_image_t obtained_closing(6, 8), expected_closing(6, 8); + gil::gray8_image_t obtained_mg(6, 8), expected_mg(6, 8); + gil::gray8_image_t obtained_top_hat(6, 8), expected_top_hat(6, 8); + gil::gray8_image_t obtained_black_hat(6, 8), expected_black_hat(6, 8); + gil::gray8_image_t obtained_dil_iter2(6, 8), expected_dil_iter2(6, 8); + gil::gray8_image_t obtained_er_iter2(6, 8), expected_er_iter2(6, 8); + gil::gray8_image_t obtained_imp_dil(4, 3), expected_imp_dil(4, 3), + original_imp_dil(4, 3); - gil::gray8_image_t original_img(6,8), obtained_dilation(6,8), expected_dilation(6,8); - gil::gray8_image_t obtained_erosion(6,8), expected_erosion(6,8); - gil::gray8_image_t obtained_opening(6,8), expected_opening(6,8); - gil::gray8_image_t obtained_closing(6,8), expected_closing(6,8); - gil::gray8_image_t obtained_mg(6,8), expected_mg(6,8); - gil::gray8_image_t obtained_top_hat(6,8), expected_top_hat(6,8); - gil::gray8_image_t obtained_black_hat(6,8), expected_black_hat(6,8); - gil::gray8_image_t obtained_dil_iter2(6,8), expected_dil_iter2(6,8); - gil::gray8_image_t obtained_er_iter2(6,8), expected_er_iter2(6,8); - gil::gray8_image_t obtained_imp_dil(4,3), expected_imp_dil(4,3), original_imp_dil(4,3); + std::vector ker_vec(9, 1.0f); // Structuring element + gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); - std::vectorker_vec(9,1.0f);//Structuring element - gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); - - pixel_fill(original_binary_vector,original_img); - pixel_fill(exp_dil,expected_dilation); - pixel_fill(exp_er,expected_erosion); - pixel_fill(exp_opening,expected_opening); - pixel_fill(exp_closing,expected_closing); - pixel_fill(exp_mg,expected_mg); - pixel_fill(exp_top_hat,expected_top_hat); - pixel_fill(exp_black_hat,expected_black_hat); - pixel_fill(exp_dil_iter2,expected_dil_iter2); - pixel_fill(orig_dil_imp,original_imp_dil); - pixel_fill(exp_dil_imp,expected_imp_dil); - pixel_fill(exp_er_iter2,expected_er_iter2); + pixel_fill(original_binary_vector, original_img); + pixel_fill(exp_dil, expected_dilation); + pixel_fill(exp_er, expected_erosion); + pixel_fill(exp_opening, expected_opening); + pixel_fill(exp_closing, expected_closing); + pixel_fill(exp_mg, expected_mg); + pixel_fill(exp_top_hat, expected_top_hat); + pixel_fill(exp_black_hat, expected_black_hat); + pixel_fill(exp_dil_iter2, expected_dil_iter2); + pixel_fill(orig_dil_imp, original_imp_dil); + pixel_fill(exp_dil_imp, expected_imp_dil); + pixel_fill(exp_er_iter2, expected_er_iter2); - // Different morphological operations are applied on the same initial image to obtain results - // of our implementation which are then compared with expected results. - gil::dilate(view(original_img), view(obtained_dilation),ker_mat,1); - gil::erode(view(original_img), view(obtained_erosion),ker_mat,1); - gil::opening(view(original_img), view(obtained_opening),ker_mat); - gil::closing(view(original_img), view(obtained_closing),ker_mat); - gil::morphological_gradient(view(original_img), view(obtained_mg),ker_mat); - gil::top_hat(view(original_img), view(obtained_top_hat),ker_mat); - gil::black_hat(view(original_img), view(obtained_black_hat),ker_mat); - gil::dilate(view(original_imp_dil), view(obtained_imp_dil),ker_mat,1); - gil::dilate(view(original_img), view(obtained_dil_iter2),ker_mat,2); - gil::erode(view(original_img), view(obtained_er_iter2), ker_mat, 2); + // Different morphological operations are applied on the same initial image to + // obtain results of our implementation which are then compared with expected + // results. + gil::dilate(view(original_img), view(obtained_dilation), ker_mat, 1); + gil::erode(view(original_img), view(obtained_erosion), ker_mat, 1); + gil::opening(view(original_img), view(obtained_opening), ker_mat); + gil::closing(view(original_img), view(obtained_closing), ker_mat); + gil::morphological_gradient(view(original_img), view(obtained_mg), ker_mat); + gil::top_hat(view(original_img), view(obtained_top_hat), ker_mat); + gil::black_hat(view(original_img), view(obtained_black_hat), ker_mat); + gil::dilate(view(original_imp_dil), view(obtained_imp_dil), ker_mat, 1); + gil::dilate(view(original_img), view(obtained_dil_iter2), ker_mat, 2); + gil::erode(view(original_img), view(obtained_er_iter2), ker_mat, 2); - // Testing obtained results with expected results. - BOOST_TEST(gil::equal_pixels(gil::view(obtained_dilation), gil::view(expected_dilation))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_erosion), gil::view(expected_erosion))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_opening), gil::view(expected_opening))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_closing), gil::view(expected_closing))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_mg), gil::view(expected_mg))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_top_hat), gil::view(expected_top_hat))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_black_hat), gil::view(expected_black_hat))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_imp_dil), gil::view(expected_imp_dil))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_dil_iter2), gil::view(expected_dil_iter2))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_er_iter2), gil::view(expected_er_iter2))); + // Testing obtained results with expected results. + BOOST_TEST(gil::equal_pixels(gil::view(obtained_dilation), + gil::view(expected_dilation))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_erosion), + gil::view(expected_erosion))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_opening), + gil::view(expected_opening))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_closing), + gil::view(expected_closing))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_mg), gil::view(expected_mg))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_top_hat), + gil::view(expected_top_hat))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_black_hat), + gil::view(expected_black_hat))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_imp_dil), + gil::view(expected_imp_dil))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_dil_iter2), + gil::view(expected_dil_iter2))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_er_iter2), + gil::view(expected_er_iter2))); - return boost::report_errors(); + return boost::report_errors(); } From 69c7cb87e1d6c17d9182ce3d623294b2ada0c8fb Mon Sep 17 00:00:00 2001 From: meshtag Date: Mon, 1 Feb 2021 17:18:22 +0530 Subject: [PATCH 18/25] pushed enum class inside namespace 'detail' and some other things --- example/morphology.cpp | 7 ++-- .../boost/gil/image_processing/morphology.hpp | 40 +++++++++++++------ 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/example/morphology.cpp b/example/morphology.cpp index 1905ef8ee8..bf2c076cff 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -32,10 +32,11 @@ int main(int argc, char **argv) { // operations considering binary conversion to be an // operation.Output_image_template argument is the common component which // will be added in all output images followed by a hyphen and the operation - // name. Example : + // name. + // Example : // ./example_morphology morphology_original.png out black_hat top_hat - // morphological_gradient dilation erosion opening closing binary Order of - // arguments entered will not matter with the exception of binary operation + // morphological_gradient dilation erosion opening closing binary + // Order of arguments entered will not matter with the exception of binary operation // used for binary morphological operations.If binary is entered through the // command line, it will always be the first operation to be applied. return -1; diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index cf6be008c5..14308a6dfb 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -14,11 +14,11 @@ namespace boost { namespace gil { -enum class morphological_operation { +namespace detail { + enum class morphological_operation { dilation, erosion, }; -namespace detail { /// \addtogroup ImageProcessing /// @{ @@ -60,14 +60,15 @@ void morph_impl(SrcView const &src_view, DstView const &dst_view, col_boundary >= 0 && col_boundary < src_view.width()) { // We ensure that we consider only those pixels which are overlapped // on a non-zero kernel_element as - if (kernel.at(flip_ker_row, flip_ker_col)) { - if (identifier == morphological_operation::dilation) { - if (src_view(col_boundary, row_boundary) > target_element) - target_element = src_view(col_boundary, row_boundary); - } else if (identifier == morphological_operation::erosion) { - if (src_view(col_boundary, row_boundary) < target_element) - target_element = src_view(col_boundary, row_boundary); - } + if(kernel.at(flip_ker_row,flip_ker_col) == 0){ + continue; + } + if (identifier == morphological_operation::dilation) { + if (src_view(col_boundary, row_boundary) > target_element) + target_element = src_view(col_boundary, row_boundary); + } else if (identifier == morphological_operation::erosion) { + if (src_view(col_boundary, row_boundary) < target_element) + target_element = src_view(col_boundary, row_boundary); } } } @@ -88,10 +89,16 @@ void morph_impl(SrcView const &src_view, DstView const &dst_view, /// \tparam DstView type of output image. /// \tparam Kernel type of structuring element. template -void morph(SrcView const &src_view, DstView &dst_view, Kernel const &ker_mat, +void morph(SrcView const &src_view, DstView const &dst_view, Kernel const &ker_mat, morphological_operation identifier) { BOOST_ASSERT(ker_mat.size() != 0 && src_view.dimensions() == dst_view.dimensions()); + gil_function_requires>(); + gil_function_requires>(); + + gil_function_requires::type, + typename color_space_type::type>>(); using d_channel_t = typename channel_type::type; using channel_t = typename channel_convert_to_unsigned::type; @@ -133,6 +140,13 @@ void difference_impl(SrcView const &src_view1, SrcView const &src_view2, template void difference(SrcView const &src_view1, SrcView const &src_view2, DiffView const &diff_view) { + gil_function_requires>(); + gil_function_requires>(); + + gil_function_requires::type, + typename color_space_type::type>>(); + for (std::size_t i = 0; i < src_view1.num_channels(); i++) { difference_impl(nth_channel_view(src_view1, i), nth_channel_view(src_view2, i), @@ -159,7 +173,7 @@ void dilate(SrcView const &src_view, IntOpView const &int_op_view, Kernel const &ker_mat, int iterations) { copy_pixels(src_view, int_op_view); for (int i = 0; i < iterations; ++i) - morph(int_op_view, int_op_view, ker_mat, morphological_operation::dilation); + morph(int_op_view, int_op_view, ker_mat, detail::morphological_operation::dilation); } /// \brief Applies morphological erosion on the input image view using given @@ -177,7 +191,7 @@ void erode(SrcView const &src_view, IntOpView const &int_op_view, Kernel const &ker_mat, int iterations) { copy_pixels(src_view, int_op_view); for (int i = 0; i < iterations; ++i) - morph(int_op_view, int_op_view, ker_mat, morphological_operation::erosion); + morph(int_op_view, int_op_view, ker_mat, detail::morphological_operation::erosion); } /// \brief Performs erosion and then dilation on the input image view . This From dc10edcce05318dc7d105cbfc7fbc4bc71f34579 Mon Sep 17 00:00:00 2001 From: meshtag Date: Tue, 2 Feb 2021 15:42:22 +0530 Subject: [PATCH 19/25] Should handle multichannel images --- .../boost/gil/image_processing/morphology.hpp | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index 14308a6dfb..4d2aeba54f 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -50,7 +50,12 @@ void morph_impl(SrcView const &src_view, DstView const &dst_view, ++kernel_col) { flip_ker_col = kernel.size() - 1 - kernel_col; // column index of flipped kernel - + + // We ensure that we consider only those pixels which are overlapped + // on a non-zero kernel_element as + if(kernel.at(flip_ker_row,flip_ker_col) == 0){ + continue; + } // index of input signal, used for checking boundary row_boundary = view_row + (kernel.center_y() - flip_ker_row); col_boundary = view_col + (kernel.center_x() - flip_ker_col); @@ -58,11 +63,7 @@ void morph_impl(SrcView const &src_view, DstView const &dst_view, // ignore input samples which are out of bound if (row_boundary >= 0 && row_boundary < src_view.height() && col_boundary >= 0 && col_boundary < src_view.width()) { - // We ensure that we consider only those pixels which are overlapped - // on a non-zero kernel_element as - if(kernel.at(flip_ker_row,flip_ker_col) == 0){ - continue; - } + if (identifier == morphological_operation::dilation) { if (src_view(col_boundary, row_boundary) > target_element) target_element = src_view(col_boundary, row_boundary); @@ -100,11 +101,7 @@ void morph(SrcView const &src_view, DstView const &dst_view, Kernel const &ker_m typename color_space_type::type, typename color_space_type::type>>(); - using d_channel_t = typename channel_type::type; - using channel_t = typename channel_convert_to_unsigned::type; - using gray_pixel_t = pixel; - using src_gray_image = image; - src_gray_image intermediate_img(src_view.dimensions()); + gil::image intermediate_img(src_view.dimensions()); for (std::size_t i = 0; i < src_view.num_channels(); i++) { morph_impl(nth_channel_view(src_view, i), @@ -239,8 +236,8 @@ template void morphological_gradient(SrcView const &src_view, DstView const &dst_view, Kernel const &ker_mat) { using namespace boost::gil; - gray8_image_t int_dilate(src_view.dimensions()), - int_erode(src_view.dimensions()); + gil::image int_dilate(src_view.dimensions()), + int_erode(src_view.dimensions()); dilate(src_view, view(int_dilate), ker_mat, 1); erode(src_view, view(int_erode), ker_mat, 1); difference(view(int_dilate), view(int_erode), dst_view); @@ -258,7 +255,7 @@ template void top_hat(SrcView const &src_view, DstView const &dst_view, Kernel const &ker_mat) { using namespace boost::gil; - gray8_image_t int_opening(src_view.dimensions()); + gil::image int_opening(src_view.dimensions()); opening(src_view, view(int_opening), ker_mat); difference(src_view, view(int_opening), dst_view); } @@ -275,7 +272,7 @@ template void black_hat(SrcView const &src_view, DstView const &dst_view, Kernel const &ker_mat) { using namespace boost::gil; - gray8_image_t int_closing(src_view.dimensions()); + gil::image int_closing(src_view.dimensions()); closing(src_view, view(int_closing), ker_mat); difference(view(int_closing), src_view, dst_view); } From d393ab4e95c9fc78b4f398a09ebd9094f8ad57e6 Mon Sep 17 00:00:00 2001 From: meshtag Date: Mon, 8 Feb 2021 11:34:09 +0530 Subject: [PATCH 20/25] Clang formatting attempt --- example/clang-format/.clang-format | 299 +++++------------- example/morphology.cpp | 7 +- .../boost/gil/image_processing/morphology.hpp | 57 ++-- 3 files changed, 123 insertions(+), 240 deletions(-) diff --git a/example/clang-format/.clang-format b/example/clang-format/.clang-format index 4394c4a091..7b531fdac2 100644 --- a/example/clang-format/.clang-format +++ b/example/clang-format/.clang-format @@ -1,71 +1,30 @@ -# Annotated clang-format configuration for Boost.GIL -# -# Based in clang-format 5.0 options: -# http://releases.llvm.org/5.0.0/tools/clang/docs/ClangFormatStyleOptions.html -# ---- -Language: Cpp - -# The style used for all options not specifically set in the configuration. -# NOTE: Strive to specify all options, so it is unnecessary to inherit any defaults. -#BasedOnStyle: WebKit+Chromium - -# Use no space offset for class access modifiers, eg. public. +Language: Cpp +# BasedOnStyle: LLVM AccessModifierOffset: -4 - -# How to horizontally align arguments after an open bracket (angle and square too). -AlignAfterOpenBracket: AlwaysBreak - -# Align the assignment operators of consecutive lines. -AlignConsecutiveAssignments: true - -# Align the declaration names of consecutive lines. +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false - -# How to align backslashes in escaped newlines, i.e. preprocessor macro continuation. AlignEscapedNewlines: Right - -# Horizontally align operands of binary and ternary expressions. -AlignOperands: true - -# Align trailing comments in consecutive lines +AlignOperands: true AlignTrailingComments: true - -# If the function declaration doesn't fit on a line, allow putting all parameters -# of a function declaration onto the next line even if BinPackParameters is false. +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true - -# Allows contracting simple braced statements to a single line. -AllowShortBlocksOnASingleLine: false - -# Allows contracting short case labels to a single line. -AllowShortCaseLabelsOnASingleLine: true - -# Dependent on the value, int f() { return 0; } can be put on a single line. +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: None - -# Dependent on the value, if (a) return; can be put on a single line. -AllowShortIfStatementsOnASingleLine: false - -# Dependent on the value, while (true) continue; can be put on a single line. +AllowShortLambdasOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never AllowShortLoopsOnASingleLine: false - -# This option is deprecated and is retained for backwards compatibility. -#AlwaysBreakAfterDefinitionReturnType: AllDefinitions - -# Always break before multiline string literals. -AlwaysBreakBeforeMultilineStrings: true - -# Always break after the template<...> of a template declaration. -AlwaysBreakTemplateDeclarations: true - -# Place function call arguments on the same or separate lines. -# See also AllowAllParametersOfDeclarationOnNextLine. -BinPackParameters: false - -# Custom control of individual brace wrapping cases -# See BreakBeforeBraces: Custom +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true BraceWrapping: + AfterCaseLabel: true AfterClass: true AfterControlStatement: true AfterEnum: true @@ -73,191 +32,105 @@ BraceWrapping: AfterNamespace: false AfterObjCDeclaration: true AfterStruct: true - AfterUnion: true - BeforeCatch: true + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false BeforeElse: true + BeforeLambdaBody: true IndentBraces: false - + SplitEmptyFunction: false + SplitEmptyRecord: true + SplitEmptyNamespace: false BreakBeforeBinaryOperators: None - -# Custom, then BraceWrapping applies BreakBeforeBraces: Custom - -# In the class inheritance break before : and , if there is multiple inheritance. -BreakBeforeInheritanceComma: true - -# Place ternary operators after line breaks, so ? and : lead lines with operands. +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true - -# Break constructor initializers before the colon and commas, -# and align the commas with the colon. -BreakConstructorInitializers: BeforeComma - -# Allow breaking string literals when formatting. +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true - -# Keep lines under 100 characters/columns long. ColumnLimit: 100 - -# Regular expression for comments with special meaning, which should not be changed. -CommentPragmas: '^!<' - -# Consecutive namespace declarations will be on the same line wrapping -# any overflowing namespace. +CommentPragmas: '^ IWYU pragma:' CompactNamespaces: true - -# If constructor initializers don't fit on a line, put each initializer on its own line. -ConstructorInitializerAllOnOneLineOrOnePerLine: true - -# Number of characters to use for indentation of constructor initializer lists. +ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 - -# Indent width for line continuations. ContinuationIndentWidth: 4 - -# Format braced lists as best suited for C++11 braced lists. Cpp11BracedListStyle: true - -# Whether to analyze formatted file for the most common alignment of & and *. -# If true, thenPointerAlignment is then used only as fallback. +DeriveLineEnding: true DerivePointerAlignment: false - -# Disables formatting completely. -DisableFormat: false - -# Whether clang-format should detect function calls and definitions formatting -# with one parameter per line. EXPERIMENTAL +DisableFormat: false ExperimentalAutoDetectBinPacking: false - -# Add missing namespace end comments and fix invalid existing ones. FixNamespaceComments: true - -# Expect no for-each MACROS, for sake! -ForEachMacros: [] - -# Regular expressions for categories used for ordering #includes -# TODO: Refine -# Regex: '^<(c?(assert|complex|ctype|errno|fenv|float|inttypes|iso646|limits|locale|math|setjmp|signal|stdalign|stdarg|stdbool|stddef|stdint|stdio|stdlib|string|tgmath|time|uchar|wchar|wctype)(.h)?|(experimental/)?(algorithm|any|chrono|deque|filesystem|forward_list|functional|future|list|map|memory|memory_resource|numeric|optional|ratio|regex|set|string|string_view|system_error|tuple|type_traits|unordered_map|unordered_set|utility|vector)|array|atomic|bitset|charconv|codecvt|compare|complex|condition_variable|cstdatomic|exception|exception_list|execution|execution_policy|fstream|initializer_list|iomanip|ios|iosfwd|iostream|istream|iterator|limits|locale|mutex|new|ostream|queue|random|scoped_allocator|shared_mutex|sstream|stack|stdexcept|streambuf|strstream|syncstream|thread|typeindex|typeinfo|valarray|variant)>' +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve IncludeCategories: - - Regex: '^' + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' Priority: 3 + SortPriority: 0 - Regex: '.*' - Priority: 4 - -# Regular expression to help file-to-main-include mapping. -# Boost.GIL is header-only, no mapping necessary. -#IncludeIsMainRegex: '' - -# Indent case labels one level from the switch statement. + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' IndentCaseLabels: false - -# For backward compatibility, see IndentWrappedFunctionNames -#IndentFunctionDeclarationAfterType: false - -# Indent 4 spaces at a time. +IndentGotoLabels: true +IndentPPDirectives: None IndentWidth: 4 - -# Indent if a function definition or declaration is wrapped after the type. -IndentWrappedFunctionNames: true - -# Do not keep empty line at the start of blocks. -KeepEmptyLinesAtTheStartOfBlocks: false - -# Boost.GIL does not use preprocessor macro blocks. -#MacroBlockBegin: "" -#MacroBlockEnd: "" - -# Maximum number of consecutive empty lines to keep -MaxEmptyLinesToKeep: 2 - -# Do not indent inside namespaces +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 NamespaceIndentation: None - -# -# Penalties is a complex machinery, see https://stackoverflow.com/a/46749925/151641 -# TODO: Refine - -# Penalty for breaking around an assignment operator. -PenaltyBreakAssignment: 10 - -# Penalty for breaking a function call after call(. -PenaltyBreakBeforeFirstCallParameter: 30 - -# Penalty for each line break introduced inside a comment. -PenaltyBreakComment: 10 - -# Penalty for breaking before the first << +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 - -# Penalty for each line break introduced inside a string literal. -PenaltyBreakString: 10 - -# Penalty for each character outside of the column limit. -PenaltyExcessCharacter: 100 - -# Penalty for putting the return type of a function onto its own line. -# HINT: Use auto and trailing return type -PenaltyReturnTypeOnItsOwnLine: 100 - -# Pointer and reference alignment style. +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Left - -# Prevent clang-format to attempt to re-flow comments. -# TODO: If we allow, any chance it will break Doxygen comments? -ReflowComments: false - -# Sort #include-s -SortIncludes: true - -# Sort using declarations. -# TODO: Let's see how it works, if terribly then switch off +ReflowComments: true +SortIncludes: true SortUsingDeclarations: true - -# No space inserted after C style casts. SpaceAfterCStyleCast: false - -# Insert after the 'template' keyword. +SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true - -# Fix space around assignment operators. SpaceBeforeAssignmentOperators: true - -# Do not insert space before a C++11 braced list used to initialize an object SpaceBeforeCpp11BracedList: false - -# Put space before opening parentheses only after control keywords (for/if/while...). +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements - -# No space may be inserted into (). +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false SpaceInEmptyParentheses: false - -# Number of spaces before trailing line comments (//) -SpacesBeforeTrailingComments: 2 - -# No spaces after < and before > in template argument lists. +SpacesBeforeTrailingComments: 1 SpacesInAngles: false - -# No spaces are inserted inside container literals. -SpacesInContainerLiterals: false - -# No spaces inserted into C style casts. +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false - -# No spaces will be inserted after ( and before ). SpacesInParentheses: false - -# No spaces will be inserted after [ and before ]. SpacesInSquareBrackets: false - -# Allow double brackets such as std::vector>. -Standard: Cpp11 - -# Boost.GIL uses spaces ONLY -TabWidth: 4 - +SpaceBeforeSquareBrackets: false +Standard: Latest +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseCRLF: false UseTab: Never -... +... \ No newline at end of file diff --git a/example/morphology.cpp b/example/morphology.cpp index bf2c076cff..b7603b628b 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -36,9 +36,10 @@ int main(int argc, char **argv) { // Example : // ./example_morphology morphology_original.png out black_hat top_hat // morphological_gradient dilation erosion opening closing binary - // Order of arguments entered will not matter with the exception of binary operation - // used for binary morphological operations.If binary is entered through the - // command line, it will always be the first operation to be applied. + // Order of arguments entered will not matter with the exception of binary + // operation used for binary morphological operations.If binary is entered + // through the command line, it will always be the first operation to be + // applied. return -1; } else { for (int i = 3; i < argc; ++i) diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index 4d2aeba54f..f57b7bf83a 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -15,7 +15,7 @@ namespace boost { namespace gil { namespace detail { - enum class morphological_operation { +enum class morphological_operation { dilation, erosion, }; @@ -50,12 +50,12 @@ void morph_impl(SrcView const &src_view, DstView const &dst_view, ++kernel_col) { flip_ker_col = kernel.size() - 1 - kernel_col; // column index of flipped kernel - - // We ensure that we consider only those pixels which are overlapped - // on a non-zero kernel_element as - if(kernel.at(flip_ker_row,flip_ker_col) == 0){ - continue; - } + + // We ensure that we consider only those pixels which are overlapped + // on a non-zero kernel_element as + if (kernel.at(flip_ker_row, flip_ker_col) == 0) { + continue; + } // index of input signal, used for checking boundary row_boundary = view_row + (kernel.center_y() - flip_ker_row); col_boundary = view_col + (kernel.center_x() - flip_ker_col); @@ -63,13 +63,19 @@ void morph_impl(SrcView const &src_view, DstView const &dst_view, // ignore input samples which are out of bound if (row_boundary >= 0 && row_boundary < src_view.height() && col_boundary >= 0 && col_boundary < src_view.width()) { - + if (identifier == morphological_operation::dilation) { - if (src_view(col_boundary, row_boundary) > target_element) - target_element = src_view(col_boundary, row_boundary); + // if (src_view(col_boundary, row_boundary) > target_element) + // target_element = src_view(col_boundary, row_boundary); + target_element = + std::max((int)src_view(col_boundary, row_boundary), + (int)target_element); } else if (identifier == morphological_operation::erosion) { - if (src_view(col_boundary, row_boundary) < target_element) - target_element = src_view(col_boundary, row_boundary); + // if (src_view(col_boundary, row_boundary) < target_element) + // target_element = src_view(col_boundary, row_boundary); + target_element = + std::min((int)src_view(col_boundary, row_boundary), + (int)target_element); } } } @@ -90,18 +96,19 @@ void morph_impl(SrcView const &src_view, DstView const &dst_view, /// \tparam DstView type of output image. /// \tparam Kernel type of structuring element. template -void morph(SrcView const &src_view, DstView const &dst_view, Kernel const &ker_mat, - morphological_operation identifier) { +void morph(SrcView const &src_view, DstView const &dst_view, + Kernel const &ker_mat, morphological_operation identifier) { BOOST_ASSERT(ker_mat.size() != 0 && src_view.dimensions() == dst_view.dimensions()); gil_function_requires>(); gil_function_requires>(); - gil_function_requires::type, - typename color_space_type::type>>(); + gil_function_requires< + ColorSpacesCompatibleConcept::type, + typename color_space_type::type>>(); - gil::image intermediate_img(src_view.dimensions()); + gil::image intermediate_img( + src_view.dimensions()); for (std::size_t i = 0; i < src_view.num_channels(); i++) { morph_impl(nth_channel_view(src_view, i), @@ -141,8 +148,8 @@ void difference(SrcView const &src_view1, SrcView const &src_view2, gil_function_requires>(); gil_function_requires::type, - typename color_space_type::type>>(); + typename color_space_type::type, + typename color_space_type::type>>(); for (std::size_t i = 0; i < src_view1.num_channels(); i++) { difference_impl(nth_channel_view(src_view1, i), @@ -170,7 +177,8 @@ void dilate(SrcView const &src_view, IntOpView const &int_op_view, Kernel const &ker_mat, int iterations) { copy_pixels(src_view, int_op_view); for (int i = 0; i < iterations; ++i) - morph(int_op_view, int_op_view, ker_mat, detail::morphological_operation::dilation); + morph(int_op_view, int_op_view, ker_mat, + detail::morphological_operation::dilation); } /// \brief Applies morphological erosion on the input image view using given @@ -188,7 +196,8 @@ void erode(SrcView const &src_view, IntOpView const &int_op_view, Kernel const &ker_mat, int iterations) { copy_pixels(src_view, int_op_view); for (int i = 0; i < iterations; ++i) - morph(int_op_view, int_op_view, ker_mat, detail::morphological_operation::erosion); + morph(int_op_view, int_op_view, ker_mat, + detail::morphological_operation::erosion); } /// \brief Performs erosion and then dilation on the input image view . This @@ -237,7 +246,7 @@ void morphological_gradient(SrcView const &src_view, DstView const &dst_view, Kernel const &ker_mat) { using namespace boost::gil; gil::image int_dilate(src_view.dimensions()), - int_erode(src_view.dimensions()); + int_erode(src_view.dimensions()); dilate(src_view, view(int_dilate), ker_mat, 1); erode(src_view, view(int_erode), ker_mat, 1); difference(view(int_dilate), view(int_erode), dst_view); @@ -276,7 +285,7 @@ void black_hat(SrcView const &src_view, DstView const &dst_view, closing(src_view, view(int_closing), ker_mat); difference(view(int_closing), src_view, dst_view); } -} // namespace gil /// @} +} // namespace gil } // namespace boost #endif // BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP From 9e48d48c9c1505a22d78b19cab42cfd91bff97f5 Mon Sep 17 00:00:00 2001 From: meshtag Date: Tue, 9 Feb 2021 00:04:58 +0530 Subject: [PATCH 21/25] got rid of if/else comparators for target_element --- example/clang-format/.clang-format | 298 +++++++++++++----- include/boost/gil.hpp | 22 +- .../boost/gil/image_processing/morphology.hpp | 68 ++-- 3 files changed, 260 insertions(+), 128 deletions(-) diff --git a/example/clang-format/.clang-format b/example/clang-format/.clang-format index 7b531fdac2..2f1fd348b4 100644 --- a/example/clang-format/.clang-format +++ b/example/clang-format/.clang-format @@ -1,30 +1,72 @@ -Language: Cpp -# BasedOnStyle: LLVM + +# Annotated clang-format configuration for Boost.GIL +# +# Based in clang-format 5.0 options: +# http://releases.llvm.org/5.0.0/tools/clang/docs/ClangFormatStyleOptions.html +# +--- +Language: Cpp + +# The style used for all options not specifically set in the configuration. +# NOTE: Strive to specify all options, so it is unnecessary to inherit any defaults. +#BasedOnStyle: WebKit+Chromium + +# Use no space offset for class access modifiers, eg. public. AccessModifierOffset: -4 -AlignAfterOpenBracket: Align -AlignConsecutiveMacros: false -AlignConsecutiveAssignments: false + +# How to horizontally align arguments after an open bracket (angle and square too). +AlignAfterOpenBracket: AlwaysBreak + +# Align the assignment operators of consecutive lines. +AlignConsecutiveAssignments: true + +# Align the declaration names of consecutive lines. AlignConsecutiveDeclarations: false + +# How to align backslashes in escaped newlines, i.e. preprocessor macro continuation. AlignEscapedNewlines: Right -AlignOperands: true + +# Horizontally align operands of binary and ternary expressions. +AlignOperands: true + +# Align trailing comments in consecutive lines AlignTrailingComments: true -AllowAllArgumentsOnNextLine: true -AllowAllConstructorInitializersOnNextLine: true + +# If the function declaration doesn't fit on a line, allow putting all parameters +# of a function declaration onto the next line even if BinPackParameters is false. AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: Never -AllowShortCaseLabelsOnASingleLine: false + +# Allows contracting simple braced statements to a single line. +AllowShortBlocksOnASingleLine: false + +# Allows contracting short case labels to a single line. +AllowShortCaseLabelsOnASingleLine: true + +# Dependent on the value, int f() { return 0; } can be put on a single line. AllowShortFunctionsOnASingleLine: None -AllowShortLambdasOnASingleLine: None -AllowShortIfStatementsOnASingleLine: Never + +# Dependent on the value, if (a) return; can be put on a single line. +AllowShortIfStatementsOnASingleLine: false + +# Dependent on the value, while (true) continue; can be put on a single line. AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes -BinPackArguments: true -BinPackParameters: true + +# This option is deprecated and is retained for backwards compatibility. +#AlwaysBreakAfterDefinitionReturnType: AllDefinitions + +# Always break before multiline string literals. +AlwaysBreakBeforeMultilineStrings: true + +# Always break after the template<...> of a template declaration. +AlwaysBreakTemplateDeclarations: true + +# Place function call arguments on the same or separate lines. +# See also AllowAllParametersOfDeclarationOnNextLine. +BinPackParameters: false + +# Custom control of individual brace wrapping cases +# See BreakBeforeBraces: Custom BraceWrapping: - AfterCaseLabel: true AfterClass: true AfterControlStatement: true AfterEnum: true @@ -32,105 +74,191 @@ BraceWrapping: AfterNamespace: false AfterObjCDeclaration: true AfterStruct: true - AfterUnion: false - AfterExternBlock: false - BeforeCatch: false + AfterUnion: true + BeforeCatch: true BeforeElse: true - BeforeLambdaBody: true IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: true - SplitEmptyNamespace: false + BreakBeforeBinaryOperators: None + +# Custom, then BraceWrapping applies BreakBeforeBraces: Custom -BreakBeforeInheritanceComma: false -BreakInheritanceList: BeforeColon + +# In the class inheritance break before : and , if there is multiple inheritance. +BreakBeforeInheritanceComma: true + +# Place ternary operators after line breaks, so ? and : lead lines with operands. BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: BeforeColon -BreakAfterJavaFieldAnnotations: false + +# Break constructor initializers before the colon and commas, +# and align the commas with the colon. +BreakConstructorInitializers: BeforeComma + +# Allow breaking string literals when formatting. BreakStringLiterals: true + +# Keep lines under 100 characters/columns long. ColumnLimit: 100 -CommentPragmas: '^ IWYU pragma:' + +# Regular expression for comments with special meaning, which should not be changed. +CommentPragmas: '^!<' + +# Consecutive namespace declarations will be on the same line wrapping +# any overflowing namespace. CompactNamespaces: true -ConstructorInitializerAllOnOneLineOrOnePerLine: false + +# If constructor initializers don't fit on a line, put each initializer on its own line. +ConstructorInitializerAllOnOneLineOrOnePerLine: true + +# Number of characters to use for indentation of constructor initializer lists. ConstructorInitializerIndentWidth: 4 + +# Indent width for line continuations. ContinuationIndentWidth: 4 + +# Format braced lists as best suited for C++11 braced lists. Cpp11BracedListStyle: true -DeriveLineEnding: true + +# Whether to analyze formatted file for the most common alignment of & and *. +# If true, thenPointerAlignment is then used only as fallback. DerivePointerAlignment: false -DisableFormat: false + +# Disables formatting completely. +DisableFormat: false + +# Whether clang-format should detect function calls and definitions formatting +# with one parameter per line. EXPERIMENTAL ExperimentalAutoDetectBinPacking: false + +# Add missing namespace end comments and fix invalid existing ones. FixNamespaceComments: true -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IncludeBlocks: Preserve + +# Expect no for-each MACROS, for sake! +ForEachMacros: [] + +# Regular expressions for categories used for ordering #includes +# TODO: Refine +# Regex: '^<(c?(assert|complex|ctype|errno|fenv|float|inttypes|iso646|limits|locale|math|setjmp|signal|stdalign|stdarg|stdbool|stddef|stdint|stdio|stdlib|string|tgmath|time|uchar|wchar|wctype)(.h)?|(experimental/)?(algorithm|any|chrono|deque|filesystem|forward_list|functional|future|list|map|memory|memory_resource|numeric|optional|ratio|regex|set|string|string_view|system_error|tuple|type_traits|unordered_map|unordered_set|utility|vector)|array|atomic|bitset|charconv|codecvt|compare|complex|condition_variable|cstdatomic|exception|exception_list|execution|execution_policy|fstream|initializer_list|iomanip|ios|iosfwd|iostream|istream|iterator|limits|locale|mutex|new|ostream|queue|random|scoped_allocator|shared_mutex|sstream|stack|stdexcept|streambuf|strstream|syncstream|thread|typeindex|typeinfo|valarray|variant)>' IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + - Regex: '^' Priority: 3 - SortPriority: 0 - Regex: '.*' - Priority: 1 - SortPriority: 0 -IncludeIsMainRegex: '(Test)?$' -IncludeIsMainSourceRegex: '' + Priority: 4 + +# Regular expression to help file-to-main-include mapping. +# Boost.GIL is header-only, no mapping necessary. +#IncludeIsMainRegex: '' + +# Indent case labels one level from the switch statement. IndentCaseLabels: false -IndentGotoLabels: true -IndentPPDirectives: None + +# For backward compatibility, see IndentWrappedFunctionNames +#IndentFunctionDeclarationAfterType: false + +# Indent 4 spaces at a time. IndentWidth: 4 -IndentWrappedFunctionNames: false -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: true -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 + +# Indent if a function definition or declaration is wrapped after the type. +IndentWrappedFunctionNames: true + +# Do not keep empty line at the start of blocks. +KeepEmptyLinesAtTheStartOfBlocks: false + +# Boost.GIL does not use preprocessor macro blocks. +#MacroBlockBegin: "" +#MacroBlockEnd: "" + +# Maximum number of consecutive empty lines to keep +MaxEmptyLinesToKeep: 2 + +# Do not indent inside namespaces NamespaceIndentation: None -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true -PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 + +# +# Penalties is a complex machinery, see https://stackoverflow.com/a/46749925/151641 +# TODO: Refine + +# Penalty for breaking around an assignment operator. +PenaltyBreakAssignment: 10 + +# Penalty for breaking a function call after call(. +PenaltyBreakBeforeFirstCallParameter: 30 + +# Penalty for each line break introduced inside a comment. +PenaltyBreakComment: 10 + +# Penalty for breaking before the first << PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 + +# Penalty for each line break introduced inside a string literal. +PenaltyBreakString: 10 + +# Penalty for each character outside of the column limit. +PenaltyExcessCharacter: 100 + +# Penalty for putting the return type of a function onto its own line. +# HINT: Use auto and trailing return type +PenaltyReturnTypeOnItsOwnLine: 100 + +# Pointer and reference alignment style. PointerAlignment: Left -ReflowComments: true -SortIncludes: true + +# Prevent clang-format to attempt to re-flow comments. +# TODO: If we allow, any chance it will break Doxygen comments? +ReflowComments: false + +# Sort #include-s +SortIncludes: true + +# Sort using declarations. +# TODO: Let's see how it works, if terribly then switch off SortUsingDeclarations: true + +# No space inserted after C style casts. SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false + +# Insert after the 'template' keyword. SpaceAfterTemplateKeyword: true + +# Fix space around assignment operators. SpaceBeforeAssignmentOperators: true + +# Do not insert space before a C++11 braced list used to initialize an object SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true + +# Put space before opening parentheses only after control keywords (for/if/while...). SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyBlock: false + +# No space may be inserted into (). SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 + +# Number of spaces before trailing line comments (//) +SpacesBeforeTrailingComments: 2 + +# No spaces after < and before > in template argument lists. SpacesInAngles: false -SpacesInConditionalStatement: false -SpacesInContainerLiterals: true + +# No spaces are inserted inside container literals. +SpacesInContainerLiterals: false + +# No spaces inserted into C style casts. SpacesInCStyleCastParentheses: false + +# No spaces will be inserted after ( and before ). SpacesInParentheses: false + +# No spaces will be inserted after [ and before ]. SpacesInSquareBrackets: false -SpaceBeforeSquareBrackets: false -Standard: Latest -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION -TabWidth: 4 -UseCRLF: false + +# Allow double brackets such as std::vector>. +Standard: Cpp11 + +# Boost.GIL uses spaces ONLY +TabWidth: 4 + UseTab: Never ... \ No newline at end of file diff --git a/include/boost/gil.hpp b/include/boost/gil.hpp index a9d63d0d87..0e1eb761b5 100644 --- a/include/boost/gil.hpp +++ b/include/boost/gil.hpp @@ -21,14 +21,10 @@ #include #include #include +#include #include #include #include -#include -#include -#include -#include -#include #include #include #include @@ -43,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -51,5 +48,18 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#endif +#endif \ No newline at end of file diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index f57b7bf83a..391f7f8e85 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -65,17 +65,11 @@ void morph_impl(SrcView const &src_view, DstView const &dst_view, col_boundary >= 0 && col_boundary < src_view.width()) { if (identifier == morphological_operation::dilation) { - // if (src_view(col_boundary, row_boundary) > target_element) - // target_element = src_view(col_boundary, row_boundary); - target_element = - std::max((int)src_view(col_boundary, row_boundary), - (int)target_element); + target_element = std::max(src_view(col_boundary, row_boundary)[0], + target_element); } else if (identifier == morphological_operation::erosion) { - // if (src_view(col_boundary, row_boundary) < target_element) - // target_element = src_view(col_boundary, row_boundary); - target_element = - std::min((int)src_view(col_boundary, row_boundary), - (int)target_element); + target_element = std::min(src_view(col_boundary, row_boundary)[0], + target_element); } } } @@ -159,18 +153,17 @@ void difference(SrcView const &src_view1, SrcView const &src_view2, } } // namespace detail -// IntOpView : View utilized for performing intermediate operations which will -// contribute in creating the resultant view . /// \brief Applies morphological dilation on the input image view using given /// structuring element. It gives the maximum overlapped value to the pixel /// overlapping with the center element of structuring element. \param src_view -/// - Source/input image view. \param int_op_view - Output image view. \param -/// ker_mat - Kernel matrix/structuring element containing 0's and 1's which -/// will be used for applying dilation. \param iterations - Specifies the number -/// of times dilation is to be applied on the input image view. \tparam SrcView -/// type of source image, models gil::ImageViewConcept. \tparam IntOpView type -/// of output image, models gil::MutableImageViewConcept. \tparam Kernel type of +/// - Source/input image view. \param int_op_view - view for writing output and +/// performing intermediate operations. \param ker_mat - Kernel +/// matrix/structuring element containing 0's and 1's which will be used for +/// applying dilation. \param iterations - Specifies the number of times +/// dilation is to be applied on the input image view. \tparam SrcView type of +/// source image, models gil::ImageViewConcept. \tparam IntOpView type of output +/// image, models gil::MutableImageViewConcept. \tparam Kernel type of /// structuring element. template void dilate(SrcView const &src_view, IntOpView const &int_op_view, @@ -184,13 +177,14 @@ void dilate(SrcView const &src_view, IntOpView const &int_op_view, /// \brief Applies morphological erosion on the input image view using given /// structuring element. It gives the minimum overlapped value to the pixel /// overlapping with the center element of structuring element. \param src_view -/// - Source/input image view. \param int_op_view - Output image view. \param -/// ker_mat - Kernel matrix/structuring element containing 0's and 1's which -/// will be used for applying erosion. \param iterations - Specifies the number -/// of times erosion is to be applied on the input image view. \tparam SrcView -/// type of source image, models gil::ImageViewConcept. \tparam IntOpView type -/// of output image, models gil::MutableImageViewConcept. \tparam Kernel type of -/// structuring element. +/// - Source/input image view. \param int_op_view - view for writing output and +/// performing intermediate operations. \param ker_mat - Kernel +/// matrix/structuring element containing 0's and 1's which will be used for +/// applying erosion. \param iterations - Specifies the number of times erosion +/// is to be applied on the input image view. \tparam SrcView type of source +/// image, models gil::ImageViewConcept. \tparam IntOpView type of output image, +/// models gil::MutableImageViewConcept. \tparam Kernel type of structuring +/// element. template void erode(SrcView const &src_view, IntOpView const &int_op_view, Kernel const &ker_mat, int iterations) { @@ -202,12 +196,12 @@ void erode(SrcView const &src_view, IntOpView const &int_op_view, /// \brief Performs erosion and then dilation on the input image view . This /// operation is utilized for removing noise from images. \param src_view - -/// Source/input image view. \param int_op_view - Output image view. \param -/// ker_mat - Kernel matrix/structuring element containing 0's and 1's which -/// will be used for applying the opening operation. \tparam SrcView type of -/// source image, models gil::ImageViewConcept. \tparam IntOpView type of output -/// image, models gil::MutableImageViewConcept. \tparam Kernel type of -/// structuring element. +/// Source/input image view. \param int_op_view - view for writing output and +/// performing intermediate operations. \param ker_mat - Kernel +/// matrix/structuring element containing 0's and 1's which will be used for +/// applying the opening operation. \tparam SrcView type of source image, models +/// gil::ImageViewConcept. \tparam IntOpView type of output image, models +/// gil::MutableImageViewConcept. \tparam Kernel type of structuring element. template void opening(SrcView const &src_view, IntOpView const &int_op_view, Kernel const &ker_mat) { @@ -218,12 +212,12 @@ void opening(SrcView const &src_view, IntOpView const &int_op_view, /// \brief Performs dilation and then erosion on the input image view which is /// exactly opposite to the opening operation . Closing operation can be /// utilized for closing small holes inside foreground objects. \param src_view -/// - Source/input image view. \param int_op_view - Output image view. \param -/// ker_mat - Kernel matrix/structuring element containing 0's and 1's which -/// will be used for applying the closing operation. \tparam SrcView type of -/// source image, models gil::ImageViewConcept. \tparam IntOpView type of output -/// image, models gil::MutableImageViewConcept. \tparam Kernel type of -/// structuring element. +/// - Source/input image view. \param int_op_view - view for writing output and +/// performing intermediate operations. \param ker_mat - Kernel +/// matrix/structuring element containing 0's and 1's which will be used for +/// applying the closing operation. \tparam SrcView type of source image, models +/// gil::ImageViewConcept. \tparam IntOpView type of output image, models +/// gil::MutableImageViewConcept. \tparam Kernel type of structuring element. template void closing(SrcView const &src_view, IntOpView const &int_op_view, Kernel const &ker_mat) { From 67bf920c39de73a34b6a09814ccec354bf14464b Mon Sep 17 00:00:00 2001 From: meshtag Date: Tue, 9 Feb 2021 00:15:02 +0530 Subject: [PATCH 22/25] Adds morphology.hpp declaration in boost/gil.hpp --- include/boost/gil.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/gil.hpp b/include/boost/gil.hpp index ff67b32de8..0e1eb761b5 100644 --- a/include/boost/gil.hpp +++ b/include/boost/gil.hpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include From 985ea1ea7dd85c7fe5b575644067a2effbb565cc Mon Sep 17 00:00:00 2001 From: meshtag Date: Tue, 9 Feb 2021 00:27:33 +0530 Subject: [PATCH 23/25] Fix newline --- example/clang-format/.clang-format | 3 +-- include/boost/gil.hpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/example/clang-format/.clang-format b/example/clang-format/.clang-format index 2f1fd348b4..4394c4a091 100644 --- a/example/clang-format/.clang-format +++ b/example/clang-format/.clang-format @@ -1,4 +1,3 @@ - # Annotated clang-format configuration for Boost.GIL # # Based in clang-format 5.0 options: @@ -261,4 +260,4 @@ Standard: Cpp11 TabWidth: 4 UseTab: Never -... \ No newline at end of file +... diff --git a/include/boost/gil.hpp b/include/boost/gil.hpp index 0e1eb761b5..b98af56e6a 100644 --- a/include/boost/gil.hpp +++ b/include/boost/gil.hpp @@ -62,4 +62,4 @@ #include #include -#endif \ No newline at end of file +#endif From f365ee2a8bacba18afc3d100ff90dd194637f0d6 Mon Sep 17 00:00:00 2001 From: meshtag Date: Thu, 11 Feb 2021 00:05:17 +0530 Subject: [PATCH 24/25] (std::max)(a, b) instead of std::max(a, b) --- include/boost/gil/image_processing/morphology.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index 391f7f8e85..b74bb1a6e1 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -65,10 +65,10 @@ void morph_impl(SrcView const &src_view, DstView const &dst_view, col_boundary >= 0 && col_boundary < src_view.width()) { if (identifier == morphological_operation::dilation) { - target_element = std::max(src_view(col_boundary, row_boundary)[0], + target_element = (std::max)(src_view(col_boundary, row_boundary)[0], target_element); } else if (identifier == morphological_operation::erosion) { - target_element = std::min(src_view(col_boundary, row_boundary)[0], + target_element = (std::min)(src_view(col_boundary, row_boundary)[0], target_element); } } From 5fe337182b842efde2083d80dbcaabf81d9abef8 Mon Sep 17 00:00:00 2001 From: meshtag Date: Sat, 13 Feb 2021 10:09:50 +0530 Subject: [PATCH 25/25] Improved Formatting --- example/morphology.cpp | 204 ++++----- .../boost/gil/image_processing/morphology.hpp | 399 +++++++++--------- test/core/image_processing/morphology.cpp | 237 +++++------ 3 files changed, 425 insertions(+), 415 deletions(-) diff --git a/example/morphology.cpp b/example/morphology.cpp index b7603b628b..e54bbfef6a 100644 --- a/example/morphology.cpp +++ b/example/morphology.cpp @@ -19,109 +19,121 @@ // considered pixel of the image to be convolved. The structuring element can be // easily changed by the user. namespace gil = boost::gil; -int main(int argc, char **argv) { - std::map operations; - if (argc < 4 || argc > 11) { - throw std::invalid_argument( - "Wrong format of command line arguments.\n" - "Correct format is " - " " - "" - " \n"); - // User has to enter atleast one operation and they can enter maximum 8 - // operations considering binary conversion to be an - // operation.Output_image_template argument is the common component which - // will be added in all output images followed by a hyphen and the operation - // name. - // Example : - // ./example_morphology morphology_original.png out black_hat top_hat - // morphological_gradient dilation erosion opening closing binary - // Order of arguments entered will not matter with the exception of binary - // operation used for binary morphological operations.If binary is entered - // through the command line, it will always be the first operation to be - // applied. - return -1; - } else { - for (int i = 3; i < argc; ++i) - operations[argv[i]] = true; - } - gil::gray8_image_t img; - gil::read_image(argv[1], img, gil::png_tag{}); +int main(int argc, char** argv) +{ + std::map operations; + if (argc < 4 || argc > 11) + { + throw std::invalid_argument( + "Wrong format of command line arguments.\n" + "Correct format is " + " " + "" + " \n"); + // User has to enter atleast one operation and they can enter maximum 8 + // operations considering binary conversion to be an + // operation.Output_image_template argument is the common component which + // will be added in names of all output images followed by a hyphen and + // the operation name. + // Example : + // ./example_morphology morphology_original.png out black_hat top_hat + // morphological_gradient dilation erosion opening closing binary + // Order of arguments entered will not matter with the exception of binary + // operation used for binary morphological operations.If binary is entered + // through the command line, it will always be the first operation to be + // applied. + return -1; + } + else + { + for (int i = 3; i < argc; ++i) + operations[argv[i]] = true; + } + gil::gray8_image_t img; + gil::read_image(argv[1], img, gil::png_tag{}); - // Image can be converted to a binary format with high value as 255 and low - // value as 0 by using the threshold operator . This can be used for binary - // morphological operations . Convenient threshold for binary conversion may - // be chosen by the user. - if (operations["binary"]) { - threshold_binary(view(img), view(img), 170, 255); - std::string name = argv[2]; - name += "-binary.png"; - gil::write_view(name, view(img), gil::png_tag{}); - } + // Image can be converted to a binary format with high value as 255 and low + // value as 0 by using the threshold operator . This can be used for binary + // morphological operations . Convenient threshold for binary conversion may + // be chosen by the user. + if (operations["binary"]) + { + threshold_binary(view(img), view(img), 170, 255); + std::string name = argv[2]; + name += "-binary.png"; + gil::write_view(name, view(img), gil::png_tag{}); + } - std::vector ker_vec(9, 1.0f); // Structuring element - gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); - gil::gray8_image_t img_out_dilation(img.dimensions()), - img_out_erosion(img.dimensions()), img_out_opening(img.dimensions()); - gil::gray8_image_t img_out_closing(img.dimensions()), - img_out_mg(img.dimensions()), img_out_top_hat(img.dimensions()); - gil::gray8_image_t img_out_black_hat(img.dimensions()); + std::vector ker_vec(9, 1.0f); // Structuring element + gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); + gil::gray8_image_t img_out_dilation(img.dimensions()), img_out_erosion(img.dimensions()), + img_out_opening(img.dimensions()); + gil::gray8_image_t img_out_closing(img.dimensions()), img_out_mg(img.dimensions()), + img_out_top_hat(img.dimensions()); + gil::gray8_image_t img_out_black_hat(img.dimensions()); - // Do not pass empty input image views in functions defined below for - // morphological operations to avoid errors. - if (operations["dilation"]) { - // dilate(input_image_view,output_image_view,structuring_element,iterations) - dilate(view(img), view(img_out_dilation), ker_mat, 1); - std::string name = argv[2]; - name += "-dilation.png"; - gil::write_view(name, view(img_out_dilation), gil::png_tag{}); - } + // Do not pass empty input image views in functions defined below for + // morphological operations to avoid errors. + if (operations["dilation"]) + { + // dilate(input_image_view,output_image_view,structuring_element,iterations) + dilate(view(img), view(img_out_dilation), ker_mat, 1); + std::string name = argv[2]; + name += "-dilation.png"; + gil::write_view(name, view(img_out_dilation), gil::png_tag{}); + } - if (operations["erosion"]) { - // erode(input_image_view,output_image_view,structuring_element,iterations) - erode(view(img), view(img_out_erosion), ker_mat, 1); - std::string name = argv[2]; - name += "-erosion.png"; - gil::write_view(name, view(img_out_erosion), gil::png_tag{}); - } + if (operations["erosion"]) + { + // erode(input_image_view,output_image_view,structuring_element,iterations) + erode(view(img), view(img_out_erosion), ker_mat, 1); + std::string name = argv[2]; + name += "-erosion.png"; + gil::write_view(name, view(img_out_erosion), gil::png_tag{}); + } - if (operations["opening"]) { - // opening(input_image_view,output_image_view,structuring_element) - opening(view(img), view(img_out_opening), ker_mat); - std::string name = argv[2]; - name += "-opening.png"; - gil::write_view(name, view(img_out_opening), gil::png_tag{}); - } + if (operations["opening"]) + { + // opening(input_image_view,output_image_view,structuring_element) + opening(view(img), view(img_out_opening), ker_mat); + std::string name = argv[2]; + name += "-opening.png"; + gil::write_view(name, view(img_out_opening), gil::png_tag{}); + } - if (operations["closing"]) { - // closing(input_image_view,output_image_view,structuring_element) - closing(view(img), view(img_out_closing), ker_mat); - std::string name = argv[2]; - name += "-closing.png"; - gil::write_view(name, view(img_out_closing), gil::png_tag{}); - } + if (operations["closing"]) + { + // closing(input_image_view,output_image_view,structuring_element) + closing(view(img), view(img_out_closing), ker_mat); + std::string name = argv[2]; + name += "-closing.png"; + gil::write_view(name, view(img_out_closing), gil::png_tag{}); + } - if (operations["morphological_gradient"]) { - // morphological_gradient(input_image_view,output_image_view,structuring_element) - morphological_gradient(view(img), view(img_out_mg), ker_mat); - std::string name = argv[2]; - name += "-morphological_gradient.png"; - gil::write_view(name, view(img_out_mg), gil::png_tag{}); - } + if (operations["morphological_gradient"]) + { + // morphological_gradient(input_image_view,output_image_view,structuring_element) + morphological_gradient(view(img), view(img_out_mg), ker_mat); + std::string name = argv[2]; + name += "-morphological_gradient.png"; + gil::write_view(name, view(img_out_mg), gil::png_tag{}); + } - if (operations["top_hat"]) { - // top_hat(input_image_view,output_image_view,structuring_element) - top_hat(view(img), view(img_out_top_hat), ker_mat); - std::string name = argv[2]; - name += "-top_hat.png"; - gil::write_view(name, view(img_out_top_hat), gil::png_tag{}); - } + if (operations["top_hat"]) + { + // top_hat(input_image_view,output_image_view,structuring_element) + top_hat(view(img), view(img_out_top_hat), ker_mat); + std::string name = argv[2]; + name += "-top_hat.png"; + gil::write_view(name, view(img_out_top_hat), gil::png_tag{}); + } - if (operations["black_hat"]) { - // black_hat(input_image_view,output_image_view,structuring_element) - black_hat(view(img), view(img_out_black_hat), ker_mat); - std::string name = argv[2]; - name += "-black_hat.png"; - gil::write_view(name, view(img_out_black_hat), gil::png_tag{}); - } + if (operations["black_hat"]) + { + // black_hat(input_image_view,output_image_view,structuring_element) + black_hat(view(img), view(img_out_black_hat), ker_mat); + std::string name = argv[2]; + name += "-black_hat.png"; + gil::write_view(name, view(img_out_black_hat), gil::png_tag{}); + } } diff --git a/include/boost/gil/image_processing/morphology.hpp b/include/boost/gil/image_processing/morphology.hpp index b74bb1a6e1..1149b2c165 100644 --- a/include/boost/gil/image_processing/morphology.hpp +++ b/include/boost/gil/image_processing/morphology.hpp @@ -12,12 +12,16 @@ #include #include -namespace boost { -namespace gil { -namespace detail { -enum class morphological_operation { - dilation, - erosion, +namespace boost +{ +namespace gil +{ +namespace detail +{ +enum class morphological_operation +{ + dilation, + erosion, }; /// \addtogroup ImageProcessing /// @{ @@ -25,261 +29,272 @@ enum class morphological_operation { /// \brief Implements morphological operations at pixel level.This function /// compares neighbouring pixel values according to the kernel and choose /// minimum/mamximum neighbouring pixel value and assigns it to the pixel under -/// consideration. \param src_view - Source/Input image view. \param dst_view - -/// View which stores the final result of operations performed by this function. +/// consideration. +/// \param src_view - Source/Input image view. +/// \param dst_view - View which stores the final result of operations performed by this function. /// \param kernel - Kernel matrix/structuring element containing 0's and 1's -/// which will be used for applying the required morphological operation. \param -/// identifier - Indicates the type of morphological operation to be applied. +/// which will be used for applying the required morphological operation. +/// \param identifier - Indicates the type of morphological operation to be applied. /// \tparam SrcView type of source image. /// \tparam DstView type of output image. /// \tparam Kernel type of structuring element. template -void morph_impl(SrcView const &src_view, DstView const &dst_view, - Kernel const &kernel, morphological_operation identifier) { - std::ptrdiff_t flip_ker_row, flip_ker_col, row_boundary, col_boundary; - typename channel_type::type target_element; - for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) { - for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) { - target_element = src_view(view_col, view_row); - for (std::size_t kernel_row = 0; kernel_row < kernel.size(); - ++kernel_row) { - flip_ker_row = - kernel.size() - 1 - kernel_row; // row index of flipped kernel +void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel, + morphological_operation identifier) +{ + std::ptrdiff_t flip_ker_row, flip_ker_col, row_boundary, col_boundary; + typename channel_type::type target_element; + for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row) + { + for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col) + { + target_element = src_view(view_col, view_row); + for (std::size_t kernel_row = 0; kernel_row < kernel.size(); ++kernel_row) + { + flip_ker_row = kernel.size() - 1 - kernel_row; // row index of flipped kernel - for (std::size_t kernel_col = 0; kernel_col < kernel.size(); - ++kernel_col) { - flip_ker_col = - kernel.size() - 1 - kernel_col; // column index of flipped kernel + for (std::size_t kernel_col = 0; kernel_col < kernel.size(); ++kernel_col) + { + flip_ker_col = kernel.size() - 1 - kernel_col; // column index of flipped kernel - // We ensure that we consider only those pixels which are overlapped - // on a non-zero kernel_element as - if (kernel.at(flip_ker_row, flip_ker_col) == 0) { - continue; - } - // index of input signal, used for checking boundary - row_boundary = view_row + (kernel.center_y() - flip_ker_row); - col_boundary = view_col + (kernel.center_x() - flip_ker_col); + // We ensure that we consider only those pixels which are overlapped + // on a non-zero kernel_element as + if (kernel.at(flip_ker_row, flip_ker_col) == 0) + { + continue; + } + // index of input signal, used for checking boundary + row_boundary = view_row + (kernel.center_y() - flip_ker_row); + col_boundary = view_col + (kernel.center_x() - flip_ker_col); - // ignore input samples which are out of bound - if (row_boundary >= 0 && row_boundary < src_view.height() && - col_boundary >= 0 && col_boundary < src_view.width()) { + // ignore input samples which are out of bound + if (row_boundary >= 0 && row_boundary < src_view.height() && + col_boundary >= 0 && col_boundary < src_view.width()) + { - if (identifier == morphological_operation::dilation) { - target_element = (std::max)(src_view(col_boundary, row_boundary)[0], - target_element); - } else if (identifier == morphological_operation::erosion) { - target_element = (std::min)(src_view(col_boundary, row_boundary)[0], - target_element); + if (identifier == morphological_operation::dilation) + { + target_element = + (std::max)(src_view(col_boundary, row_boundary)[0], target_element); + } + else if (identifier == morphological_operation::erosion) + { + target_element = + (std::min)(src_view(col_boundary, row_boundary)[0], target_element); + } + } + } } - } + dst_view(view_col, view_row) = target_element; } - } - dst_view(view_col, view_row) = target_element; } - } } /// \brief Checks feasibility of the desired operation and passes parameter /// values to the function morph_impl alongwith individual channel views of the -/// input image. \param src_view - Source/Input image view. \param dst_view - -/// View which stores the final result of operations performed by this function. +/// input image. +/// \param src_view - Source/Input image view. +/// \param dst_view - View which stores the final result of operations performed by this function. /// \param kernel - Kernel matrix/structuring element containing 0's and 1's -/// which will be used for applying the required morphological operation. \param -/// identifier - Indicates the type of morphological operation to be applied. +/// which will be used for applying the required morphological operation. +/// \param identifier - Indicates the type of morphological operation to be applied. /// \tparam SrcView type of source image. /// \tparam DstView type of output image. /// \tparam Kernel type of structuring element. template -void morph(SrcView const &src_view, DstView const &dst_view, - Kernel const &ker_mat, morphological_operation identifier) { - BOOST_ASSERT(ker_mat.size() != 0 && - src_view.dimensions() == dst_view.dimensions()); - gil_function_requires>(); - gil_function_requires>(); +void morph(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat, + morphological_operation identifier) +{ + BOOST_ASSERT(ker_mat.size() != 0 && src_view.dimensions() == dst_view.dimensions()); + gil_function_requires>(); + gil_function_requires>(); - gil_function_requires< - ColorSpacesCompatibleConcept::type, - typename color_space_type::type>>(); + gil_function_requires::type, + typename color_space_type::type>>(); - gil::image intermediate_img( - src_view.dimensions()); + gil::image intermediate_img(src_view.dimensions()); - for (std::size_t i = 0; i < src_view.num_channels(); i++) { - morph_impl(nth_channel_view(src_view, i), - nth_channel_view(view(intermediate_img), i), ker_mat, - identifier); - } - copy_pixels(view(intermediate_img), dst_view); + for (std::size_t i = 0; i < src_view.num_channels(); i++) + { + morph_impl(nth_channel_view(src_view, i), nth_channel_view(view(intermediate_img), i), + ker_mat, identifier); + } + copy_pixels(view(intermediate_img), dst_view); } /// \brief Calculates the difference between pixel values of first image_view -/// and second image_view. \param src_view1 - First parameter for subtraction of -/// views. \param src_view2 - Second parameter for subtraction of views. \param -/// diff_view - View containing result of the subtraction of second view from -/// the first view. \tparam SrcView type of source/Input images used for -/// subtraction. \tparam DiffView type of image view containing the result of -/// subtraction. +/// and second image_view. +/// \param src_view1 - First parameter for subtraction of views. +/// \param src_view2 - Second parameter for subtraction of views. +/// \param diff_view - View containing result of the subtraction of second view from +/// the first view. +/// \tparam SrcView type of source/Input images used for subtraction. +/// \tparam DiffView type of image view containing the result of subtraction. template -void difference_impl(SrcView const &src_view1, SrcView const &src_view2, - DiffView const &diff_view) { - for (std::ptrdiff_t view_row = 0; view_row < src_view1.height(); ++view_row) - for (std::ptrdiff_t view_col = 0; view_col < src_view1.width(); ++view_col) - diff_view(view_col, view_row) = - src_view1(view_col, view_row) - src_view2(view_col, view_row); +void difference_impl(SrcView const& src_view1, SrcView const& src_view2, DiffView const& diff_view) +{ + for (std::ptrdiff_t view_row = 0; view_row < src_view1.height(); ++view_row) + for (std::ptrdiff_t view_col = 0; view_col < src_view1.width(); ++view_col) + diff_view(view_col, view_row) = + src_view1(view_col, view_row) - src_view2(view_col, view_row); } /// \brief Passes parameter values to the function 'difference_impl' alongwith -/// individual channel views of input images. \param src_view1 - First parameter -/// for subtraction of views. \param src_view2 - Second parameter for -/// subtraction of views. \param diff_view - View containing result of the -/// subtraction of second view from the first view. \tparam SrcView type of -/// source/Input images used for subtraction. \tparam DiffView type of image -/// view containing the result of subtraction. +/// individual channel views of input images. +/// \param src_view1 - First parameter for subtraction of views. +/// \param src_view2 - Second parameter for subtraction of views. +/// \param diff_view - View containing result of the subtraction of second view from the first view. +/// \tparam SrcView type of source/Input images used for subtraction. +/// \tparam DiffView type of image view containing the result of subtraction. template -void difference(SrcView const &src_view1, SrcView const &src_view2, - DiffView const &diff_view) { - gil_function_requires>(); - gil_function_requires>(); +void difference(SrcView const& src_view1, SrcView const& src_view2, DiffView const& diff_view) +{ + gil_function_requires>(); + gil_function_requires>(); - gil_function_requires::type, - typename color_space_type::type>>(); + gil_function_requires::type, typename color_space_type::type>>(); - for (std::size_t i = 0; i < src_view1.num_channels(); i++) { - difference_impl(nth_channel_view(src_view1, i), - nth_channel_view(src_view2, i), - nth_channel_view(diff_view, i)); - } + for (std::size_t i = 0; i < src_view1.num_channels(); i++) + { + difference_impl(nth_channel_view(src_view1, i), nth_channel_view(src_view2, i), + nth_channel_view(diff_view, i)); + } } } // namespace detail - /// \brief Applies morphological dilation on the input image view using given /// structuring element. It gives the maximum overlapped value to the pixel /// overlapping with the center element of structuring element. \param src_view -/// - Source/input image view. \param int_op_view - view for writing output and -/// performing intermediate operations. \param ker_mat - Kernel -/// matrix/structuring element containing 0's and 1's which will be used for -/// applying dilation. \param iterations - Specifies the number of times -/// dilation is to be applied on the input image view. \tparam SrcView type of -/// source image, models gil::ImageViewConcept. \tparam IntOpView type of output -/// image, models gil::MutableImageViewConcept. \tparam Kernel type of -/// structuring element. +/// - Source/input image view. +/// \param int_op_view - view for writing output and performing intermediate operations. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for +/// applying dilation. +/// \param iterations - Specifies the number of times dilation is to be applied on the input image +/// view. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template -void dilate(SrcView const &src_view, IntOpView const &int_op_view, - Kernel const &ker_mat, int iterations) { - copy_pixels(src_view, int_op_view); - for (int i = 0; i < iterations; ++i) - morph(int_op_view, int_op_view, ker_mat, - detail::morphological_operation::dilation); +void dilate(SrcView const& src_view, IntOpView const& int_op_view, Kernel const& ker_mat, + int iterations) +{ + copy_pixels(src_view, int_op_view); + for (int i = 0; i < iterations; ++i) + morph(int_op_view, int_op_view, ker_mat, detail::morphological_operation::dilation); } /// \brief Applies morphological erosion on the input image view using given /// structuring element. It gives the minimum overlapped value to the pixel -/// overlapping with the center element of structuring element. \param src_view -/// - Source/input image view. \param int_op_view - view for writing output and -/// performing intermediate operations. \param ker_mat - Kernel -/// matrix/structuring element containing 0's and 1's which will be used for -/// applying erosion. \param iterations - Specifies the number of times erosion -/// is to be applied on the input image view. \tparam SrcView type of source -/// image, models gil::ImageViewConcept. \tparam IntOpView type of output image, -/// models gil::MutableImageViewConcept. \tparam Kernel type of structuring -/// element. +/// overlapping with the center element of structuring element. +/// \param src_view - Source/input image view. +/// \param int_op_view - view for writing output and performing intermediate operations. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for +/// applying erosion. +/// \param iterations - Specifies the number of times erosion is to be applied on the input +/// image view. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template -void erode(SrcView const &src_view, IntOpView const &int_op_view, - Kernel const &ker_mat, int iterations) { - copy_pixels(src_view, int_op_view); - for (int i = 0; i < iterations; ++i) - morph(int_op_view, int_op_view, ker_mat, - detail::morphological_operation::erosion); +void erode(SrcView const& src_view, IntOpView const& int_op_view, Kernel const& ker_mat, + int iterations) +{ + copy_pixels(src_view, int_op_view); + for (int i = 0; i < iterations; ++i) + morph(int_op_view, int_op_view, ker_mat, detail::morphological_operation::erosion); } /// \brief Performs erosion and then dilation on the input image view . This -/// operation is utilized for removing noise from images. \param src_view - -/// Source/input image view. \param int_op_view - view for writing output and -/// performing intermediate operations. \param ker_mat - Kernel -/// matrix/structuring element containing 0's and 1's which will be used for -/// applying the opening operation. \tparam SrcView type of source image, models -/// gil::ImageViewConcept. \tparam IntOpView type of output image, models -/// gil::MutableImageViewConcept. \tparam Kernel type of structuring element. +/// operation is utilized for removing noise from images. +/// \param src_view - Source/input image view. +/// \param int_op_view - view for writing output and performing intermediate operations. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for +/// applying the opening operation. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template -void opening(SrcView const &src_view, IntOpView const &int_op_view, - Kernel const &ker_mat) { - erode(src_view, int_op_view, ker_mat, 1); - dilate(int_op_view, int_op_view, ker_mat, 1); +void opening(SrcView const& src_view, IntOpView const& int_op_view, Kernel const& ker_mat) +{ + erode(src_view, int_op_view, ker_mat, 1); + dilate(int_op_view, int_op_view, ker_mat, 1); } /// \brief Performs dilation and then erosion on the input image view which is /// exactly opposite to the opening operation . Closing operation can be -/// utilized for closing small holes inside foreground objects. \param src_view -/// - Source/input image view. \param int_op_view - view for writing output and -/// performing intermediate operations. \param ker_mat - Kernel -/// matrix/structuring element containing 0's and 1's which will be used for -/// applying the closing operation. \tparam SrcView type of source image, models -/// gil::ImageViewConcept. \tparam IntOpView type of output image, models -/// gil::MutableImageViewConcept. \tparam Kernel type of structuring element. +/// utilized for closing small holes inside foreground objects. +/// \param src_view - Source/input image view. +/// \param int_op_view - view for writing output and performing intermediate operations. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for +/// applying the closing operation. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam IntOpView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template -void closing(SrcView const &src_view, IntOpView const &int_op_view, - Kernel const &ker_mat) { - dilate(src_view, int_op_view, ker_mat, 1); - erode(int_op_view, int_op_view, ker_mat, 1); +void closing(SrcView const& src_view, IntOpView const& int_op_view, Kernel const& ker_mat) +{ + dilate(src_view, int_op_view, ker_mat, 1); + erode(int_op_view, int_op_view, ker_mat, 1); } /// \brief Calculates the difference between image views generated after /// applying dilation dilation and erosion on an image . The resultant image -/// will look like the outline of the object(s) present in the image. \param -/// src_view - Source/input image view. \param dst_view - Destination view which -/// will store the final result of morphological gradient operation. \param -/// ker_mat - Kernel matrix/structuring element containing 0's and 1's which -/// will be used for applying the morphological gradient operation. \tparam -/// SrcView type of source image, models gil::ImageViewConcept. \tparam DstView -/// type of output image, models gil::MutableImageViewConcept. \tparam Kernel -/// type of structuring element. +/// will look like the outline of the object(s) present in the image. +/// \param src_view - Source/input image view. +/// \param dst_view - Destination view which will store the final result of morphological +/// gradient operation. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which +/// will be used for applying the morphological gradient operation. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam DstView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template -void morphological_gradient(SrcView const &src_view, DstView const &dst_view, - Kernel const &ker_mat) { - using namespace boost::gil; - gil::image int_dilate(src_view.dimensions()), - int_erode(src_view.dimensions()); - dilate(src_view, view(int_dilate), ker_mat, 1); - erode(src_view, view(int_erode), ker_mat, 1); - difference(view(int_dilate), view(int_erode), dst_view); +void morphological_gradient(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gil::image int_dilate(src_view.dimensions()), + int_erode(src_view.dimensions()); + dilate(src_view, view(int_dilate), ker_mat, 1); + erode(src_view, view(int_erode), ker_mat, 1); + difference(view(int_dilate), view(int_erode), dst_view); } /// \brief Calculates the difference between input image view and the view -/// generated by opening operation on the input image view. \param src_view - -/// Source/input image view. \param dst_view - Destination view which will store -/// the final result of top hat operation. \param ker_mat - Kernel -/// matrix/structuring element containing 0's and 1's which will be used for -/// applying the top hat operation. \tparam SrcView type of source image, models -/// gil::ImageViewConcept. \tparam DstView type of output image, models -/// gil::MutableImageViewConcept. \tparam Kernel type of structuring element. +/// generated by opening operation on the input image view. +/// \param src_view - Source/input image view. +/// \param dst_view - Destination view which will store the final result of top hat operation. +/// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's which will be used for +/// applying the top hat operation. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam DstView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template -void top_hat(SrcView const &src_view, DstView const &dst_view, - Kernel const &ker_mat) { - using namespace boost::gil; - gil::image int_opening(src_view.dimensions()); - opening(src_view, view(int_opening), ker_mat); - difference(src_view, view(int_opening), dst_view); +void top_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gil::image int_opening(src_view.dimensions()); + opening(src_view, view(int_opening), ker_mat); + difference(src_view, view(int_opening), dst_view); } /// \brief Calculates the difference between closing of the input image and -/// input image. \param src_view - Source/input image view. \param dst_view - -/// Destination view which will store the final result of black hat operation. +/// input image. +/// \param src_view - Source/input image view. +/// \param dst_view - Destination view which will store the final result of black hat operation. /// \param ker_mat - Kernel matrix/structuring element containing 0's and 1's -/// which will be used for applying the black hat operation. \tparam SrcView -/// type of source image, models gil::ImageViewConcept. \tparam DstView type of -/// output image, models gil::MutableImageViewConcept. \tparam Kernel type of -/// structuring element. +/// which will be used for applying the black hat operation. +/// \tparam SrcView type of source image, models gil::ImageViewConcept. +/// \tparam DstView type of output image, models gil::MutableImageViewConcept. +/// \tparam Kernel type of structuring element. template -void black_hat(SrcView const &src_view, DstView const &dst_view, - Kernel const &ker_mat) { - using namespace boost::gil; - gil::image int_closing(src_view.dimensions()); - closing(src_view, view(int_closing), ker_mat); - difference(view(int_closing), src_view, dst_view); +void black_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat) +{ + using namespace boost::gil; + gil::image int_closing(src_view.dimensions()); + closing(src_view, view(int_closing), ker_mat); + difference(view(int_closing), src_view, dst_view); } /// @} -} // namespace gil -} // namespace boost +}} // namespace boost::gil #endif // BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP diff --git a/test/core/image_processing/morphology.cpp b/test/core/image_processing/morphology.cpp index 2d132e596e..b57f605723 100644 --- a/test/core/image_processing/morphology.cpp +++ b/test/core/image_processing/morphology.cpp @@ -14,140 +14,123 @@ namespace gil = boost::gil; // This function helps us fill pixels of a view given as 2nd argument with // elements of the vector given as 1st argument. -void pixel_fill(std::vector> &original_binary_vector, - boost::gil::gray8_image_t &original_img) { - for (std::ptrdiff_t view_row = 0; view_row < view(original_img).height(); - ++view_row) { - for (std::ptrdiff_t view_col = 0; view_col < view(original_img).width(); - ++view_col) { - view(original_img)(view_col, view_row) = - gil::gray8_pixel_t(original_binary_vector[view_row][view_col]); +void pixel_fill(std::vector>& original_binary_vector, + boost::gil::gray8_image_t& original_img) +{ + for (std::ptrdiff_t view_row = 0; view_row < view(original_img).height(); ++view_row) + { + for (std::ptrdiff_t view_col = 0; view_col < view(original_img).width(); ++view_col) + { + view(original_img)(view_col, view_row) = + gil::gray8_pixel_t(original_binary_vector[view_row][view_col]); + } } - } } -int main() { - std::vector> original_binary_vector{ - {0, 0, 0, 0, 0, 0}, {0, 0, 127, 144, 143, 0}, - {0, 0, 128, 0, 142, 0}, {0, 0, 129, 0, 141, 0}, - {0, 0, 130, 140, 139, 0}, {0, 0, 131, 0, 0, 0}, - {0, 0, 132, 137, 136, 138}, {0, 0, 133, 134, 135, 0}}; - std::vector> orig_dil_imp{ - {255, 100, 100, 100}, {100, 100, 100, 100}, {100, 100, 100, 100}}; - // All vectors defined below will be used for creating expected image views - // which are supposed to match the views obtained after applying morphological - // operations. - std::vector> exp_dil{ - {0, 127, 144, 144, 144, 143}, {0, 128, 144, 144, 144, 143}, - {0, 129, 144, 144, 144, 143}, {0, 130, 140, 142, 142, 142}, - {0, 131, 140, 141, 141, 141}, {0, 132, 140, 140, 140, 139}, - {0, 133, 137, 137, 138, 138}, {0, 133, 137, 137, 138, 138}}; - // Following vector intends to check result of dilation operation when it is - // applied 2 times on the original image. - std::vector> exp_dil_iter2{ - {128, 144, 144, 144, 144, 144}, {129, 144, 144, 144, 144, 144}, - {130, 144, 144, 144, 144, 144}, {131, 144, 144, 144, 144, 144}, - {132, 140, 142, 142, 142, 142}, {133, 140, 141, 141, 141, 141}, - {133, 140, 140, 140, 140, 140}, {133, 137, 137, 138, 138, 138}}; - std::vector> exp_er{ - {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, {0, 0, 0, 132, 0, 0}}; - // Following vector intends to check result of erosion operation when it is - // applied 2 times on the original image. - std::vector> exp_er_iter2{ - {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; - std::vector> exp_opening{ - {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, - {0, 0, 132, 132, 132, 0}, {0, 0, 132, 132, 132, 0}}; - std::vector> exp_closing{ - {0, 0, 127, 144, 143, 143}, {0, 0, 127, 144, 143, 143}, - {0, 0, 128, 140, 142, 142}, {0, 0, 129, 140, 141, 141}, - {0, 0, 130, 140, 139, 139}, {0, 0, 131, 137, 137, 138}, - {0, 0, 132, 137, 137, 138}, {0, 0, 133, 137, 137, 138}}; - std::vector> exp_mg{ - {0, 127, 144, 144, 144, 143}, {0, 128, 144, 144, 144, 143}, - {0, 129, 144, 144, 144, 143}, {0, 130, 140, 142, 142, 142}, - {0, 131, 140, 141, 141, 141}, {0, 132, 140, 140, 140, 139}, - {0, 133, 137, 137, 138, 138}, {0, 133, 137, 5, 138, 138}}; - std::vector> exp_top_hat{ - {0, 0, 0, 0, 0, 0}, {0, 0, 127, 144, 143, 0}, {0, 0, 128, 0, 142, 0}, - {0, 0, 129, 0, 141, 0}, {0, 0, 130, 140, 139, 0}, {0, 0, 131, 0, 0, 0}, - {0, 0, 0, 5, 4, 138}, {0, 0, 1, 2, 3, 0}}; - std::vector> exp_black_hat{ - {0, 0, 127, 144, 143, 143}, {0, 0, 0, 0, 0, 143}, - {0, 0, 0, 140, 0, 142}, {0, 0, 0, 140, 0, 141}, - {0, 0, 0, 0, 0, 139}, {0, 0, 0, 137, 137, 138}, - {0, 0, 0, 0, 1, 0}, {0, 0, 0, 3, 2, 138}}; - std::vector> exp_dil_imp{ - {255, 255, 100, 100}, {255, 255, 100, 100}, {100, 100, 100, 100}}; +int main() +{ + std::vector> original_binary_vector{ + {0, 0, 0, 0, 0, 0}, {0, 0, 127, 144, 143, 0}, {0, 0, 128, 0, 142, 0}, + {0, 0, 129, 0, 141, 0}, {0, 0, 130, 140, 139, 0}, {0, 0, 131, 0, 0, 0}, + {0, 0, 132, 137, 136, 138}, {0, 0, 133, 134, 135, 0}}; + std::vector> orig_dil_imp{ + {255, 100, 100, 100}, {100, 100, 100, 100}, {100, 100, 100, 100}}; + // All vectors defined below will be used for creating expected image views + // which are supposed to match the views obtained after applying morphological + // operations. + std::vector> exp_dil{ + {0, 127, 144, 144, 144, 143}, {0, 128, 144, 144, 144, 143}, {0, 129, 144, 144, 144, 143}, + {0, 130, 140, 142, 142, 142}, {0, 131, 140, 141, 141, 141}, {0, 132, 140, 140, 140, 139}, + {0, 133, 137, 137, 138, 138}, {0, 133, 137, 137, 138, 138}}; + // Following vector intends to check result of dilation operation when it is + // applied 2 times on the original image. + std::vector> exp_dil_iter2{ + {128, 144, 144, 144, 144, 144}, {129, 144, 144, 144, 144, 144}, + {130, 144, 144, 144, 144, 144}, {131, 144, 144, 144, 144, 144}, + {132, 140, 142, 142, 142, 142}, {133, 140, 141, 141, 141, 141}, + {133, 140, 140, 140, 140, 140}, {133, 137, 137, 138, 138, 138}}; + std::vector> exp_er{ + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 132, 0, 0}}; + // Following vector intends to check result of erosion operation when it is + // applied 2 times on the original image. + std::vector> exp_er_iter2{ + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}; + std::vector> exp_opening{ + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 132, 132, 132, 0}, {0, 0, 132, 132, 132, 0}}; + std::vector> exp_closing{ + {0, 0, 127, 144, 143, 143}, {0, 0, 127, 144, 143, 143}, {0, 0, 128, 140, 142, 142}, + {0, 0, 129, 140, 141, 141}, {0, 0, 130, 140, 139, 139}, {0, 0, 131, 137, 137, 138}, + {0, 0, 132, 137, 137, 138}, {0, 0, 133, 137, 137, 138}}; + std::vector> exp_mg{{0, 127, 144, 144, 144, 143}, {0, 128, 144, 144, 144, 143}, + {0, 129, 144, 144, 144, 143}, {0, 130, 140, 142, 142, 142}, + {0, 131, 140, 141, 141, 141}, {0, 132, 140, 140, 140, 139}, + {0, 133, 137, 137, 138, 138}, {0, 133, 137, 5, 138, 138}}; + std::vector> exp_top_hat{{0, 0, 0, 0, 0, 0}, {0, 0, 127, 144, 143, 0}, + {0, 0, 128, 0, 142, 0}, {0, 0, 129, 0, 141, 0}, + {0, 0, 130, 140, 139, 0}, {0, 0, 131, 0, 0, 0}, + {0, 0, 0, 5, 4, 138}, {0, 0, 1, 2, 3, 0}}; + std::vector> exp_black_hat{ + {0, 0, 127, 144, 143, 143}, {0, 0, 0, 0, 0, 143}, {0, 0, 0, 140, 0, 142}, + {0, 0, 0, 140, 0, 141}, {0, 0, 0, 0, 0, 139}, {0, 0, 0, 137, 137, 138}, + {0, 0, 0, 0, 1, 0}, {0, 0, 0, 3, 2, 138}}; + std::vector> exp_dil_imp{ + {255, 255, 100, 100}, {255, 255, 100, 100}, {100, 100, 100, 100}}; - gil::gray8_image_t original_img(6, 8), obtained_dilation(6, 8), - expected_dilation(6, 8); - gil::gray8_image_t obtained_erosion(6, 8), expected_erosion(6, 8); - gil::gray8_image_t obtained_opening(6, 8), expected_opening(6, 8); - gil::gray8_image_t obtained_closing(6, 8), expected_closing(6, 8); - gil::gray8_image_t obtained_mg(6, 8), expected_mg(6, 8); - gil::gray8_image_t obtained_top_hat(6, 8), expected_top_hat(6, 8); - gil::gray8_image_t obtained_black_hat(6, 8), expected_black_hat(6, 8); - gil::gray8_image_t obtained_dil_iter2(6, 8), expected_dil_iter2(6, 8); - gil::gray8_image_t obtained_er_iter2(6, 8), expected_er_iter2(6, 8); - gil::gray8_image_t obtained_imp_dil(4, 3), expected_imp_dil(4, 3), - original_imp_dil(4, 3); + gil::gray8_image_t original_img(6, 8), obtained_dilation(6, 8), expected_dilation(6, 8); + gil::gray8_image_t obtained_erosion(6, 8), expected_erosion(6, 8); + gil::gray8_image_t obtained_opening(6, 8), expected_opening(6, 8); + gil::gray8_image_t obtained_closing(6, 8), expected_closing(6, 8); + gil::gray8_image_t obtained_mg(6, 8), expected_mg(6, 8); + gil::gray8_image_t obtained_top_hat(6, 8), expected_top_hat(6, 8); + gil::gray8_image_t obtained_black_hat(6, 8), expected_black_hat(6, 8); + gil::gray8_image_t obtained_dil_iter2(6, 8), expected_dil_iter2(6, 8); + gil::gray8_image_t obtained_er_iter2(6, 8), expected_er_iter2(6, 8); + gil::gray8_image_t obtained_imp_dil(4, 3), expected_imp_dil(4, 3), original_imp_dil(4, 3); - std::vector ker_vec(9, 1.0f); // Structuring element - gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); + std::vector ker_vec(9, 1.0f); // Structuring element + gil::detail::kernel_2d ker_mat(ker_vec.begin(), ker_vec.size(), 1, 1); - pixel_fill(original_binary_vector, original_img); - pixel_fill(exp_dil, expected_dilation); - pixel_fill(exp_er, expected_erosion); - pixel_fill(exp_opening, expected_opening); - pixel_fill(exp_closing, expected_closing); - pixel_fill(exp_mg, expected_mg); - pixel_fill(exp_top_hat, expected_top_hat); - pixel_fill(exp_black_hat, expected_black_hat); - pixel_fill(exp_dil_iter2, expected_dil_iter2); - pixel_fill(orig_dil_imp, original_imp_dil); - pixel_fill(exp_dil_imp, expected_imp_dil); - pixel_fill(exp_er_iter2, expected_er_iter2); + pixel_fill(original_binary_vector, original_img); + pixel_fill(exp_dil, expected_dilation); + pixel_fill(exp_er, expected_erosion); + pixel_fill(exp_opening, expected_opening); + pixel_fill(exp_closing, expected_closing); + pixel_fill(exp_mg, expected_mg); + pixel_fill(exp_top_hat, expected_top_hat); + pixel_fill(exp_black_hat, expected_black_hat); + pixel_fill(exp_dil_iter2, expected_dil_iter2); + pixel_fill(orig_dil_imp, original_imp_dil); + pixel_fill(exp_dil_imp, expected_imp_dil); + pixel_fill(exp_er_iter2, expected_er_iter2); - // Different morphological operations are applied on the same initial image to - // obtain results of our implementation which are then compared with expected - // results. - gil::dilate(view(original_img), view(obtained_dilation), ker_mat, 1); - gil::erode(view(original_img), view(obtained_erosion), ker_mat, 1); - gil::opening(view(original_img), view(obtained_opening), ker_mat); - gil::closing(view(original_img), view(obtained_closing), ker_mat); - gil::morphological_gradient(view(original_img), view(obtained_mg), ker_mat); - gil::top_hat(view(original_img), view(obtained_top_hat), ker_mat); - gil::black_hat(view(original_img), view(obtained_black_hat), ker_mat); - gil::dilate(view(original_imp_dil), view(obtained_imp_dil), ker_mat, 1); - gil::dilate(view(original_img), view(obtained_dil_iter2), ker_mat, 2); - gil::erode(view(original_img), view(obtained_er_iter2), ker_mat, 2); + // Different morphological operations are applied on the same initial image to + // obtain results of our implementation which are then compared with expected + // results. + gil::dilate(view(original_img), view(obtained_dilation), ker_mat, 1); + gil::erode(view(original_img), view(obtained_erosion), ker_mat, 1); + gil::opening(view(original_img), view(obtained_opening), ker_mat); + gil::closing(view(original_img), view(obtained_closing), ker_mat); + gil::morphological_gradient(view(original_img), view(obtained_mg), ker_mat); + gil::top_hat(view(original_img), view(obtained_top_hat), ker_mat); + gil::black_hat(view(original_img), view(obtained_black_hat), ker_mat); + gil::dilate(view(original_imp_dil), view(obtained_imp_dil), ker_mat, 1); + gil::dilate(view(original_img), view(obtained_dil_iter2), ker_mat, 2); + gil::erode(view(original_img), view(obtained_er_iter2), ker_mat, 2); - // Testing obtained results with expected results. - BOOST_TEST(gil::equal_pixels(gil::view(obtained_dilation), - gil::view(expected_dilation))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_erosion), - gil::view(expected_erosion))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_opening), - gil::view(expected_opening))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_closing), - gil::view(expected_closing))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_mg), gil::view(expected_mg))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_top_hat), - gil::view(expected_top_hat))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_black_hat), - gil::view(expected_black_hat))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_imp_dil), - gil::view(expected_imp_dil))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_dil_iter2), - gil::view(expected_dil_iter2))); - BOOST_TEST(gil::equal_pixels(gil::view(obtained_er_iter2), - gil::view(expected_er_iter2))); + // Testing obtained results with expected results. + BOOST_TEST(gil::equal_pixels(gil::view(obtained_dilation), gil::view(expected_dilation))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_erosion), gil::view(expected_erosion))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_opening), gil::view(expected_opening))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_closing), gil::view(expected_closing))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_mg), gil::view(expected_mg))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_top_hat), gil::view(expected_top_hat))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_black_hat), gil::view(expected_black_hat))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_imp_dil), gil::view(expected_imp_dil))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_dil_iter2), gil::view(expected_dil_iter2))); + BOOST_TEST(gil::equal_pixels(gil::view(obtained_er_iter2), gil::view(expected_er_iter2))); - return boost::report_errors(); + return boost::report_errors(); }