به نام خدا : ماژول Operations on arrays زیر مجموعه ای از ماژول Core functionality هستش؛ این ماژول شامل هر عملیاتی که بشه رو آرایه/ماتریس/تصویر ها اعمال کرد هستش!
توابع محاسبات بیتی :
1) تابع bitwise_and : محاسبه AND بیتی عناصر متناظر دو آرایه و یا یک آرایه و یک scalar.
تعریف تابع :
1 2 3 4 5 |
CV_EXPORTS_W void bitwise_and( InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray() ); |
توضیح پارامترها :
- src1 و src2 : آرایه های ورودی
- dst : آرایه خروجی با اندازه و نوعی برابر با آرایه های ورودی.
کد نمونه : اگه درباره AND بیتی چیزی نمیدونید یه سرچی کنید، وگرنه کد زیر رو درست متوجه نمیشید؛ تو تصویر dst1 که همه پیکسل ها با صفر، اند بیتی میشن فلذا مقدار همه پیکسل ها 0 میشه ( به خاطر همین سیاه شده تصویر خروجی )؛ تو تصاویر dst2 تا dst4، تاثیر بیت کم ارزش و پر ارزش رو مشاهده میکنید ( که خب میشه برا پنهان کردن داده ها، داخل بیت های کم ارزش تصاویر استفاده کرد، کسی هم متوجه تغییر تو عکس نمیشه، البته ربطی به این مطلب نداره ولی خب خواستم بگم میشه اینکارو کرد، قبلا تو این مطلب همچین کاری کردم : Steganography )؛ تصویر dst5 هم که دقیقا مثل تصویر ورودی هستش؛ تصویر dst7 تا dst9 هم که اومدم هربار مقدار یه کانال رو دست نزدم و بقیه کانال ها رو 0 کردم، اینطوری تصویر خروجی فقط حاوی 1 کانال میشه ( استخراج کانال! )؛ تصویر dst10 هم که از روی بیکاری نوشتم!؛ یه تصویر ( img3 ) ایجاد کردم که کل پیکسل هاش سیاه ( 0 ) هستش، بعد مرکزشو پیدا کردم و تمام نقاطی که داخل شعاع مدنظر من هستن رو سفید ( 255 ) کردم بعد تابع bitwise_and...؛ تمام کارای که تو dst7 تا dst10 کردم رو توی dst6 بصورت یکجا انجام دادم که مشاهده میکنید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
void operations_on_arrays_example1::bitwise_and_test() { cv::Mat img1 = cv::imread("C:/Users/Mahdi/Desktop/bitwise_and_src1.jpg"); cv::Mat img2 = cv::imread("C:/Users/Mahdi/Desktop/bitwise_and_src2.png"); cv::Mat img3(img1.size(), img1.type(), cv::Scalar::all(0)); cv::Mat dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9, dst10; cv::bitwise_and(img1, cv::Scalar(001,001,000), dst1); // 000 DEC = 00000000 BIN cv::bitwise_and(img1, cv::Scalar(015,015,015), dst2); // 015 DEC = 00001111 BIN cv::bitwise_and(img1, cv::Scalar(240,240,240), dst3); // 240 DEC = 11110000 BIN cv::bitwise_and(img1, cv::Scalar(240,240,240), dst4); // 128 DEC = 10000000 BIN cv::bitwise_and(img1, cv::Scalar(255,255,255), dst5); // 255 DEC = 11111111 BIN cv::bitwise_and(img1, img2, dst6); cv::bitwise_and(img1, cv::Scalar(255,000,000), dst7); // blue channel cv::bitwise_and(img1, cv::Scalar(000,255,000), dst8); // green channel cv::bitwise_and(img1, cv::Scalar(000,000,255), dst9); // red channel cv::Point center(img1.cols/2, img1.rows/2); int radius = 200; for (int i=0; i<img1.cols; i++) { for (int j=0; j<img1.rows; j++) { double distance = cv::norm( cv::Point(i,j) - center ); if(distance < radius) { img3.at<cv::Vec3b>(cv::Point(i,j)) = cv::Vec3b(255,255,255); } } } cv::bitwise_and(img1, img3, dst10); // ??? cv::imwrite("C:/Users/Mahdi/Desktop/bitwise_and_dst1.jpg", dst1); cv::imwrite("C:/Users/Mahdi/Desktop/bitwise_and_dst2.jpg", dst2); cv::imwrite("C:/Users/Mahdi/Desktop/bitwise_and_dst3.jpg", dst3); cv::imwrite("C:/Users/Mahdi/Desktop/bitwise_and_dst4.jpg", dst4); cv::imwrite("C:/Users/Mahdi/Desktop/bitwise_and_dst5.jpg", dst5); cv::imwrite("C:/Users/Mahdi/Desktop/bitwise_and_dst6.jpg", dst6); cv::imwrite("C:/Users/Mahdi/Desktop/bitwise_and_dst7.jpg", dst7); cv::imwrite("C:/Users/Mahdi/Desktop/bitwise_and_dst8.jpg", dst8); cv::imwrite("C:/Users/Mahdi/Desktop/bitwise_and_dst9.jpg", dst9); cv::imwrite("C:/Users/Mahdi/Desktop/bitwise_and_dst10.jpg", dst10); } |
نتیجه کد بالا :
2) تابع bitwise_not : محاسبه NOT بیتی عناصر یک آرایه و یا یک scalar.
تعریف تابع :
1 2 3 4 |
CV_EXPORTS_W void bitwise_not( InputArray src, OutputArray dst, InputArray mask = noArray() ); |
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
3) تابع bitwise_or : محاسبه OR بیتی عناصر متناظر دو آرایه و یا یک آرایه و یک scalar.
تعریف تابع :
1 2 3 4 5 |
CV_EXPORTS_W void bitwise_or( InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray() ); |
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
4) تابع bitwise_xor : محاسبه XOR بیتی عناصر متناظر دو آرایه و یا یک آرایه و یک scalar.
تعریف تابع :
1 2 3 4 5 |
CV_EXPORTS_W void bitwise_xor( InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray() ); |
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
توابع الحاق افقی / عمودی، 2 یا چند ماتریس :
1) تابع hconcat : الحاق افقی 2 یا چند ماتریس.
تعاریف تابع :
1 2 3 |
CV_EXPORTS void hconcat(const Mat* src, size_t nsrc, OutputArray dst); CV_EXPORTS void hconcat(InputArray src1, InputArray src2, OutputArray dst); CV_EXPORTS_W void hconcat(InputArrayOfArrays src, OutputArray dst); |
کد نمونه ( برای تعریف 1 ) :
1 2 3 4 5 6 7 8 9 10 |
cv::Mat matArray[] = { cv::Mat(4, 1, CV_8UC1, cv::Scalar(1)), cv::Mat(4, 1, CV_8UC1, cv::Scalar(2)), cv::Mat(4, 1, CV_8UC1, cv::Scalar(3)),}; cv::Mat out; cv::hconcat( matArray, 3, out ); //out: //[1, 2, 3; // 1, 2, 3; // 1, 2, 3; // 1, 2, 3] |
کد نمونه ( برای تعریف 2 ) :
1 2 3 4 5 6 7 8 9 10 11 12 |
cv::Mat_<float> A = (cv::Mat_<float>(3, 2) << 1, 4, 2, 5, 3, 6); cv::Mat_<float> B = (cv::Mat_<float>(3, 2) << 7, 10, 8, 11, 9, 12); cv::Mat C; cv::hconcat(A, B, C); //C: //[1, 4, 7, 10; // 2, 5, 8, 11; // 3, 6, 9, 12] |
کد نمونه ( برای تعریف 3 ) :
1 2 3 4 5 6 7 8 9 10 |
std::vector<cv::Mat> matrices = { cv::Mat(4, 1, CV_8UC1, cv::Scalar(1)), cv::Mat(4, 1, CV_8UC1, cv::Scalar(2)), cv::Mat(4, 1, CV_8UC1, cv::Scalar(3)),}; cv::Mat out; cv::hconcat( matrices, out ); //out: //[1, 2, 3; // 1, 2, 3; // 1, 2, 3; // 1, 2, 3] |
2) تابع vconcat : الحاق عمودی 2 یا چند ماتریس.
تعاریف تابع :
1 2 3 |
CV_EXPORTS void vconcat(const Mat* src, size_t nsrc, OutputArray dst); CV_EXPORTS void vconcat(InputArray src1, InputArray src2, OutputArray dst); CV_EXPORTS_W void vconcat(InputArrayOfArrays src, OutputArray dst); |
کد نمونه ( برای تعریف 1 ) :
1 2 3 4 5 6 7 8 9 |
cv::Mat matArray[] = { cv::Mat(1, 4, CV_8UC1, cv::Scalar(1)), cv::Mat(1, 4, CV_8UC1, cv::Scalar(2)), cv::Mat(1, 4, CV_8UC1, cv::Scalar(3)),}; cv::Mat out; cv::vconcat( matArray, 3, out ); //out: //[1, 1, 1, 1; // 2, 2, 2, 2; // 3, 3, 3, 3] |
کد نمونه ( برای تعریف 2 ) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
cv::Mat_<float> A = (cv::Mat_<float>(3, 2) << 1, 7, 2, 8, 3, 9); cv::Mat_<float> B = (cv::Mat_<float>(3, 2) << 4, 10, 5, 11, 6, 12); cv::Mat C; cv::vconcat(A, B, C); //C: //[1, 7; // 2, 8; // 3, 9; // 4, 10; // 5, 11; // 6, 12] |
کد نمونه ( برای تعریف 3 ) :
1 2 3 4 5 6 7 8 9 |
std::vector<cv::Mat> matrices = { cv::Mat(1, 4, CV_8UC1, cv::Scalar(1)), cv::Mat(1, 4, CV_8UC1, cv::Scalar(2)), cv::Mat(1, 4, CV_8UC1, cv::Scalar(3)),}; cv::Mat out; cv::vconcat( matrices, out ); //out: //[1, 1, 1, 1; // 2, 2, 2, 2; // 3, 3, 3, 3] |
توابع عملیات های ریاضی :
1.1) تابع add : محاسبه مجموع عناصر متناظر دو آرایه و یا یک آرایه و یک scalar.
\( \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) + \texttt{src2}(I)) \quad \texttt{if mask}(I) \ne0 \)
تعریف تابع :
1 2 3 4 5 6 |
CV_EXPORTS_W void add( InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray(), int dtype = -1 ); |
توضیح پارامترها :
- src1 و src2 : آرایه های ورودی با اندازه و نوعی یکسان.
- dst : آرایه خروجی با اندازه و تعداد کانالی برابر با آرایه های ورودی.
کد نمونه : در عکس لوگو OpenCV، زمینه رو سیاه کردم تا تو محاسبات تاثیری نذاره ( مقدار تمام کانال های رنگ سیاه، 0 هستش و سفید 255 )
1 2 3 4 5 6 7 8 9 10 11 12 |
void operations_on_arrays_example1::add_test() { cv::Mat img1 = cv::imread("C:/Users/Mahdi/Desktop/add_src1.jpg"); cv::Mat img2 = cv::imread("C:/Users/Mahdi/Desktop/add_src2.png"); cv::Mat dst1, dst2; cv::add(img1, img2, dst1); cv::add(img1, cv::Scalar::all(100), dst2); cv::imwrite("C:/Users/Mahdi/Desktop/add_dst1.jpg", dst1); cv::imwrite("C:/Users/Mahdi/Desktop/add_dst2.jpg", dst2); } |
نتیجه کد بالا :
1.2) تابع addWeighted : محاسبه وزن دار مجموع هر عنصر دو آرایه و یا یک آرایه و یک scalar.
\( \texttt{dst} (I)= \texttt{saturate} ( \texttt{src1} (I)* \texttt{alpha} + \texttt{src2} (I)* \texttt{beta} + \texttt{gamma} ) \)
تعریف تابع :
1 2 3 4 5 6 7 8 |
CV_EXPORTS_W void addWeighted( InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype = -1 ); |
توضیح پارامترها :
- src1 و src2 : آرایه های ورودی با اندازه و تعداد کانالی یکسان.
- alpha : وزن / ضریب ( weight ) آرایه اولی ( src1 ).
- beta : وزن / ضریب ( weight ) آرایه دومی ( src2 ).
- gamma : مقداری ثابت ( scalar ) که به خروجی اضافه میشود.
- dst : آرایه خروجی با اندازه و تعداد کانالی برابر با آرایه های ورودی.
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 |
void operations_on_arrays_example1::addWeighted_test() { cv::Mat img1 = cv::imread("C:/Users/Mahdi/Desktop/add_src1.jpg"); cv::Mat img2 = cv::imread("C:/Users/Mahdi/Desktop/add_src2.png"); cv::Mat dst1, dst2; cv::addWeighted(img1, 0.2, img2, 1, 0, dst1); cv::addWeighted(img1, 1, img2, 0.2, 0, dst2); cv::imwrite("C:/Users/Mahdi/Desktop/addWeighted_dst1.jpg", dst1); cv::imwrite("C:/Users/Mahdi/Desktop/addWeighted_dst2.jpg", dst2); } |
نتیجه کد بالا : تصاویر ورودی، همون تصاویر ورودی تابع add هستند.
1.3) تابع scaleAdd :
\( \texttt{dst} (I)= \texttt{scale} \cdot \texttt{src1} (I) + \texttt{src2} (I) \)
تعریف تابع :
1 |
CV_EXPORTS_W void scaleAdd(InputArray src1, double alpha, InputArray src2, OutputArray dst); |
2.1) تابع subtract : محاسبه تفریق عناصر متناظر دو آرایه و یا یک آرایه و یک scalar.
\( \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) - \texttt{src2}(I)) \quad \texttt{if mask}(I) \ne0 \)
تعریف تابع :
1 2 3 4 5 6 |
CV_EXPORTS_W void subtract( InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray(), int dtype = -1 ); |
2.2) تابع absdiff : محاسبه تفاوت مطلق ( absolute difference ) بین عناصر متناظر دو آرایه یا بین یک آرایه و یک scalar.
\( \texttt{dst}(I) = \texttt{saturate} (| \texttt{src1}(I) - \texttt{src2}(I)|) \)
تعریف تابع :
1 |
CV_EXPORTS_W void absdiff(InputArray src1, InputArray src2, OutputArray dst); |
توضیح پارامترها :
- src1 و src2 : آرایه های ورودی با اندازه و نوعی یکسان.
- dst : آرایه خروجی با اندازه و نوعی برابر با آرایه های ورودی.
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 |
void operations_on_arrays_example1::absdiff_test() { cv::Mat img1 = cv::imread("C:/Users/Mahdi/Desktop/absdiff_src1.jpg"); cv::Mat img2 = cv::imread("C:/Users/Mahdi/Desktop/absdiff_src2.jpg"); cv::Mat dst1, dst2; cv::absdiff(img1, img2, dst1); cv::absdiff(img1, cv::Scalar::all(100), dst2); cv::imwrite("C:/Users/Mahdi/Desktop/absdiff_dst1.jpg", dst1); cv::imwrite("C:/Users/Mahdi/Desktop/absdiff_dst2.jpg", dst2); } |
نتیجه کد بالا :
3) تابع divide : محاسبه تقسیم عناصر متناظر دو آرایه و یا یک آرایه و یک scalar؛ کانال های آرایه های چند کاناله به طور مستقل پردازش میشوند.
\( \texttt{dst(I) = saturate(src1(I)*scale/src2(I))} \)
\( \texttt{dst(I) = saturate(scale/src2(I))} \)
تعاریف تابع :
1 2 |
CV_EXPORTS_W void divide(InputArray src1, InputArray src2, OutputArray dst, double scale = 1, int dtype = -1); CV_EXPORTS_W void divide(double scale, InputArray src2, OutputArray dst, int dtype = -1); |
4) تابع multiply : محاسبه ضرب عناصر متناظر دو آرایه؛ کانال های آرایه های چند کاناله به طور مستقل پردازش میشوند.
\( \texttt{dst} (I)= \texttt{saturate} ( \texttt{scale} \cdot \texttt{src1} (I) \cdot \texttt{src2} (I)) \)
تعریف تابع :
1 2 3 4 5 6 |
CV_EXPORTS_W void multiply( InputArray src1, InputArray src2, OutputArray dst, double scale = 1, int dtype = -1 ); |
5) تابع sqrt : محاسبه جذر ( ریشه 2 ) عناصر یک آرایه.
تعریف تابع :
1 |
CV_EXPORTS_W void sqrt(InputArray src, OutputArray dst); |
6) تابع pow : محاسبه توان ( n ام ) عناصر یک آرایه.
\( \text{dst} (I) = \begin{cases} \text{src}(I)^{power} & \text{if $power$ is integer} \\ |\text{src}(I)|^{power} & \text{otherwise} \end{cases} \)
تعریف تابع :
1 |
CV_EXPORTS_W void pow(InputArray src, double power, OutputArray dst); |
7) تابع log : محاسبه لگاریتم ( در مبنای 10 ) عناصر متناظر یک آرایه.
\( \texttt{dst} (I) = \log (\texttt{src}(I)) \)
تعریف تابع :
1 |
CV_EXPORTS_W void log(InputArray src, OutputArray dst); |
8) تابع exp : محاسبه e ( عدد نپر ) به توان عناصر متناظر یک آرایه.
\( \texttt{dst} [I] = e^{ src(I) } \)
تعریف تابع :
1 |
CV_EXPORTS_W void exp(InputArray src, OutputArray dst); |
توابع : جدا کردن تمام کانال های یک آرایه؛ ادغام چندین کانال؛ انتقال کانال های دلخواه یک آرایه به آرایه دیگر؛ اضافه کردن یک کانال به آرایه؛ جدا کردن یک کانال از آرایه.
1) تابع split : جدا کردن کانال های یک آرایه چند کاناله.
تعاریف تابع :
1 2 |
CV_EXPORTS void split(const Mat& src, Mat* mvbegin); CV_EXPORTS_W void split(InputArray m, OutputArrayOfArrays mv); |
2) تابع merge : ادغام کانال های یک آرایه چند کاناله.
تعاریف تابع :
1 2 |
CV_EXPORTS void merge(const Mat* mv, size_t count, OutputArray dst); CV_EXPORTS_W void merge(InputArrayOfArrays mv, OutputArray dst); |
3) تابع mixChannels : کپی کردن کانال های مشخص شده از آرایه های ورودی به کانال های مشخص شده در آرایه های خروجی.
تعاریف تابع :
1 2 3 |
CV_EXPORTS void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs); CV_EXPORTS void mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst, const int* fromTo, size_t npairs); CV_EXPORTS_W void mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst, const std::vector<int>& fromTo); |
4) تابع extractChannel : استخراج یک کانال از آرایه ورودی.
تعریف تابع :
1 |
CV_EXPORTS_W void extractChannel(InputArray src, OutputArray dst, int coi); |
5) تابع insertChannel : اضافه کردن یک کانال به آرایه ورودی.
تعریف تابع :
1 |
CV_EXPORTS_W void insertChannel(InputArray src, InputOutputArray dst, int coi); |
توابع ایجاد ارقام تصادفی :
کلاس RNG
مولد اعداد تصادفی؛ این کلاس در حال حاضر از توزیع های یکنواخت ( uniform ) و گاوسی / عادی ( Gaussian / Normal ) پشتیبانی میکند؛ ( اگه درست فهمیده باشم ) مولد اعداد تصادفی uniform، از الگوریتم Multiply-With-Carry، معرفی شده توسط George Marsaglia، استفاده میکند؛ مولد اعداد تصادفی Gaussian، از الگوریتم Ziggurat، معرفی شده توسط George Marsaglia و Wai Wan Tsang، استفاده میکند.
1) سازنده ها : 2 نوع سازنده برای این کلاس تعریف شده که در تعریف اولی ( بدون پارامتر ورودی )، مقدار state پیشفرض برابر با \( 2^{32} - 1 \) میباشد؛ در تعریف دومی هم که میشه این مقدار رو تنظیم کرد؛ البته اگه مقدار state رو 0 تنظیم کنید، از مقدار پیشفرض استفاده میکنه تا از تولید اعداد تصادفی که همیشه 0 هستند، جلوگیری شود!
1 2 |
RNG(); RNG(uint64 state); |
توجه : حالا شاید سوال بشه که این state کجا بکار میاد، خب شما اگه یه سری عدد تصادفی ایجاد کنید ( مثلا به کمک تابع fill )، پروژه رو ببندید و دوباره کدتون رو اجرا کنید میبینید که همون اعداد قبلی هستش، با تغیر این state، در دفعات بعدی که پروژه اجرا میشه، اعداد تصادفی جدیدی! ایجاد میشن. ( چیزی که من متوجه شدم )
2) تابع fill : آرایه ها را با اعداد تصادفی پر میکند.
1 |
void fill( InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange = false ); |
توضیح پارامترها :
- mat : ماتریس 2 بعدی یا N بعدی؛ در حال حاضر ماتریس هایی با بیش از 4 کانال، توسط توابع OpenCV پشتیبانی نمی شوند، از Mat::reshape به عنوان یک راه حل ممکن استفاده کنید.
- distType : نوع توزیع، RNG::UNIFORM یا RNG::NORMAL.
- a : اولین پارامتر توزیع ( distribution )؛ در صورت توزیع یکنواخت ( uniform distribution )، این مقدار minimum است ( مقدار تصادفی تولید شده، شامل این مقدار میشود )، در صورت توزیع نرمال ( normal distribution )، این یک مقدار متوسط ( mean ) است.
- b : دومین پارامتر توزیع؛ در صورت توزیع یکنواخت ( uniform distribution )، این مقدار maximum است ( مقدار تصادفی تولید شده، شامل این مقدار نمیشود )، در مورد توزیع نرمال ( normal distribution )، این یک انحراف معیار ( standard deviation ) است ( مورب ماتریس انحراف استاندارد یا ماتریس انحراف استاندارد کامل ).
- saturateRange : پرچم پیش اشباع؛ فقط برای توزیع یکنواخت ( uniform distribution )؛ اگر true باشد، تابع، ابتدا a و b را به محدوده مقدار قابل قبول تبدیل می کند ( با توجه به نوع داده mat ) و سپس اعداد تصادفی توزیع شده یکنواخت در محدوده [saturate(a)، saturate(b)) تولید میکند؛ اگر false باشد، تابع، اعداد تصادفی توزیع شده یکنواخت را در محدوده اصلی [a, b) تولید میکند و سپس آنها را اشباع میکند.
کد نمونه 1 : همونطور که در این مثال میبینید، مقدار b رو 2 درنظر گرفتم، نوع mat هم که از نوع طبیعی هستش ( اعدادی که از 0 تا +n بودن رو طبیعی میگفتن فک کنم؛ در کل مهم اینه که اعشاری نیست )، فلذا مقادیر یا 0 هستن یا 1 ( در بالا گفتم که پارامتر b در نتایج قرار نداره؛ به همین خاطر مقدارشو 2 قرار دادم! )
1 2 3 4 |
cv::Mat src = cv::Mat(5, 5, CV_8UC1); cv::RNG rng; rng.fill(src, cv::RNG::UNIFORM, 0, 2); std::cout << "src = \n" << src << std::endl; |
نتیجه کد بالا :
1 2 3 4 5 |
[ 0, 0, 0, 1, 1; 0, 0, 1, 1, 0; 1, 0, 1, 0, 1; 0, 1, 0, 1, 1; 0, 0, 0, 1, 0] |
کد نمونه 2 : تو این مثال مقدار نوع داده CV_8UC1 بین 0 تا 255 هستش اما ما در تابع fill گفتیم mat رو با اعدادی بین [-DBL_MAX, DBL_MAX) پر کن، پارامتر saturateRange هم که false هستش، محدوده (0، 255) هم که به طور قابل توجهی کوچکتر از [-DBL_MAX, DBL_MAX) هستش و این یعنی 99.99% اعدادی که تولید میشن، بزرگتر از 255 هستند و این یعنی رخ دادن اشباع!؛ به همین خاطر آرایه ای که تولید میشه، عمدتاً با 0 و 255 پر میشه.
1 2 3 4 |
cv::Mat src = cv::Mat(5, 5, CV_8UC1); cv::RNG rng; rng.fill(src, cv::RNG::UNIFORM, -DBL_MAX, +DBL_MAX); std::cout << "src = \n" << src << std::endl; |
نتیجه کد بالا :
1 2 3 4 5 6 |
src = [ 0, 0, 255, 255, 255; 0, 255, 255, 255, 0; 255, 255, 0, 0, 0; 255, 255, 0, 0, 255; 0, 0, 0, 255, 0] |
3) تابع gaussian : عدد تصادفی بعدی نمونه برداری شده از توزیع گاوسی را برمی گرداند؛ این روش با استفاده از الگوریتم MWC حالت ( state ) را تغییر میدهد و عدد تصادفی بعدی را از توزیع گاوسی N(0,sigma) برمی گرداند، یعنی مقدار میانگین ( mean ) اعداد تصادفی برگشتی صفر و انحراف استاندارد ( standard deviation ) برابر با پارامتر sigma مشخص شده است.
1 |
double gaussian(double sigma); |
پارامتر sigma : انحراف معیار ( standard deviation ) توزیع ( distribution ).
4) تابع uniform : عدد تصادفی یکنواخت توزیع شده را از محدوده [a,b) برمی گرداند.
1 2 3 |
int uniform(int a, int b); float uniform(float a, float b); double uniform(double a, double b); |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
cv::RNG rng; std::string data = ""; for(int i=0; i<10; i++) data += std::to_string( rng.uniform(0, 1) ) + ", "; std::cout << data << std::endl; // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, data = ""; for(int i=0; i<10; i++) data += std::to_string( rng.uniform(0, 10) ) + ", "; std::cout << data << std::endl; // 6, 7, 9, 9, 7, 0, 6, 3, 6, 9, data = ""; for(int i=0; i<10; i++) data += std::to_string( rng.uniform((float)0, (float)1) ) + ", "; std::cout << data << std::endl; // 0.978447, 0.292190, 0.585843, 0.575060, 0.663423, 0.799779, 0.405654, 0.209686, 0.649713, 0.265440, data = ""; for(int i=0; i<10; i++) data += std::to_string( rng.uniform((double)0, (double)1) ) + ", "; std::cout << data << std::endl; // 0.624281, 0.051514, 0.658992, 0.538189, 0.346128, 0.764712, 0.452666, 0.310216, 0.594456, 0.024518, |
فرق gaussian با uniform : در مورد فرق gaussian با uniform خلاصه بگم که روش uniform، عدد خروجی بین محدوده مشخص شده هستش، همونطور که از اسمش معلومه، توزیعش، یکنواخت هستش، اما در روش gaussian، توزیع یکنواخت نیست، مقادیر بیشتر نزدیک مقدار حداقل و حداکثر هستند؛ کد زیر رو ببینید، تصاویر خرجی رو در سطح پیکسل ببینید و مقدارشون رو ببینید، و با هم مقایسه کنید ( این توضیح خوبی نیست، هرچند توضیح درست خارج از حوصله هستش، بعدا اگه نیاز شد، این قسمت رو تکمیل میکنم، باید درباره الگوریتم های این دو روش مطالعه کنم، مخصوصا روش گاوسی ) :
1 2 3 4 5 6 7 8 9 10 |
cv::Mat srcU = cv::Mat(600, 800, CV_8UC1); cv::Mat srcN = cv::Mat(600, 800, CV_8UC1); cv::RNG rng; rng.fill(srcU, cv::RNG::UNIFORM, 0, 256); rng.fill(srcN, cv::RNG::NORMAL, 0, 256); cv::imshow("srcU", srcU); cv::imshow("srcN", srcN); |
نتیجه کد بالا ( زوم 3000% ) :
توابع این قسمت برای راحتی کار با کلاس RNG ایجاد شدن!!!
1) تابع theRNG : یه شی از کلاس RNG ایجاد میکنه، با مقدار پیشفرض state.
1 |
CV_EXPORTS RNG& theRNG(); |
2) تابع setRNGSeed : تنظیم وضعیت ( state ) مولد اعداد تصادفی.
1 |
CV_EXPORTS_W void setRNGSeed(int seed); |
3) تابع randu : ایجاد یک عدد تصادفی با توزیع یکنواخت ( uniformly-distributed ) یا آرایه ای از اعداد تصادفی.
\( \texttt{low} _c \leq \texttt{dst} (I)_c < \texttt{high} _c \)
1 |
CV_EXPORTS_W void randu(InputOutputArray dst, InputArray low, InputArray high); |
کد نمونه :
1 2 3 |
cv::Mat r = cv::Mat(10, 10, CV_8UC1); cv::randu(r, cv::Scalar::all(0), cv::Scalar::all(255)); std::cout << r << std::endl; |
4) تابع randn : پر کردن آرایه با اعداد تصادفی توزیع شده معمولی ( normally distributed ).
1 |
CV_EXPORTS_W void randn(InputOutputArray dst, InputArray mean, InputArray stddev); |
کد نمونه :
1 2 3 |
cv::Mat r = cv::Mat(10, 10, CV_8UC1); cv::randn(r, cv::Scalar::all(0), cv::Scalar::all(255)); std::cout << r << std::endl; |
5) تابع randShuffle : عناصر آرایه را به صورت تصادفی با هم مخلوط میکند؛ آرایه 1 بعدی مشخص شده را با انتخاب تصادفی جفت عناصر و تعویض آنها به هم میزند؛ تعداد چنین عملیات مبادله ای \( dst.rows * dst.cols * iterFactor \) خواهد بود.
تعریف تابع :
1 |
CV_EXPORTS_W void randShuffle(InputOutputArray dst, double iterFactor = 1., RNG* rng = 0); |
توضیح پارامترها :
- dst : آرایه عددی 1 بعدی ورودی/خروجی.
- iterFactor : ضریب مقیاس که تعداد عملیات مبادله تصادفی را تعیین میکند.
- rng : مولد اعداد تصادفی اختیاری که برای به هم زدن استفاده میشود؛ اگر صفر باشد به جای آن از theRNG استفاده میشود.
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
double a[] = { 1,2,3,4,5,6,7,8,9 }; cv::Mat m0(3, 3, CV_64FC1, a); std::cout <<"0) Original matrix \n"<< m0 << std::endl; cv::Mat m1 = m0.clone(); cv::randShuffle(m1, 1); std::cout <<"1) Shuffled matrix \n"<< m1 << std::endl; cv::Mat m2 = m0.clone(); cv::randShuffle(m2, 2); std::cout <<"2) Shuffled matrix \n"<< m2 << std::endl; /* out : 0) Original matrix [1, 2, 3; 4, 5, 6; 7, 8, 9] 1) Shuffled matrix [8, 6, 2; 5, 3, 7; 1, 9, 4] 2) Shuffled matrix [5, 6, 3; 9, 2, 4; 7, 1, 8]*/ |
توابع حل معادلات جبری :
1) تابع solve :
تعریف تابع :
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
2) تابع solveCubic :
تعریف تابع :
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
3) تابع solvePoly :
تعریف تابع :
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
توابع تبدیل مختصات Polar به Cartesian و بلعکس ( توابع زیر مختصات نقاط رو تبدیل میکنن و نه عکس؛ برا تبدیل عکس میتونید از تابع warpPolar استفاده کنید ) :
1) تابع polarToCart : تبدیل مختصات Polar به Cartesian؛ محاسبه مختصات x و y بردارهای 2 بعدی.
\( \begin{array}{l} \texttt{x} (I) = \texttt{magnitude} (I) \cos ( \texttt{angle} (I)) \\ \texttt{y} (I) = \texttt{magnitude} (I) \sin ( \texttt{angle} (I)) \\ \end{array} \)
تعریف تابع :
1 2 3 4 5 6 |
CV_EXPORTS_W void polarToCart( InputArray magnitude, InputArray angle, OutputArray x, OutputArray y, bool angleInDegrees = false ); |
توضیح پارامترها :
- magnitude : آرایه ورودی اعشاری از قدر ( اندازه، بزرگی، وَتَر ) بردارهای 2 بعدی؛ میتواند یک ماتریس خالی باشد، در این صورت، تابع فرض میکند که همه قدرها 1 هستند.
- angle : آرایه ورودی اعشاری از زوایای بردارهای دو بعدی.
- x / y : آرایه خروجی مختصات x / y بردارهای 2 بعدی؛ با اندازه و نوعی برابر با angle.
- angleInDegrees : زوایا بر حسب درجه یا رادیان اندازه گیری شوند؟ ( پیشفرض : رادیان )
2) تابع cartToPolar : تبدیل مختصات Cartesian به Polar؛ محاسبه قدر و زاویه بردارهای 2 بعدی؛ زاویه ها با دقت حدود 0.3 درجه محاسبه میشوند؛ برای نقطه (0,0) زاویه 0 تنظیم شده است.
\( \begin{array}{l} \texttt{magnitude} (I)= \sqrt{\texttt{x}(I)^2+\texttt{y}(I)^2} , \\ \texttt{angle} (I)= \texttt{atan2} ( \texttt{y} (I), \texttt{x} (I))[ \cdot180 / \pi ] \end{array} \)
تعریف تابع :
1 2 3 4 5 6 |
CV_EXPORTS_W void cartToPolar( InputArray x, InputArray y, OutputArray magnitude, OutputArray angle, bool angleInDegrees = false ); |
توضیح پارامترها :
- x / y : آرایه ورودی از مختصات x / y؛ این آرایه باید اعشاری با دقت 1 یا 2 رقم باشد.
- magnitude : آرایه خروجی قدر با اندازه و نوع x.
- angle : آرایه خروجی زوایا که اندازه و نوع یکسانی با x دارد؛ زاویه ها بر حسب رادیان ( از 0 تا 2*Pi ) یا بر حسب درجه ( 0 تا 360 درجه ) اندازه گیری میشوند.
- angleInDegrees : زوایا بر حسب درجه یا رادیان اندازه گیری شوند؟ ( پیشفرض : رادیان )
توابع مرتبط با 2 تابع بالا :
1) تابع phase : محاسبه زاویه چرخش بردارهای دو بعدی.
\( \texttt{angle} (I) = \texttt{atan2} ( \texttt{y} (I), \texttt{x} (I)) \)
تعریف تابع :
1 |
CV_EXPORTS_W void phase(InputArray x, InputArray y, OutputArray angle, bool angleInDegrees = false); |
2) تابع magnitude : محاسبه قدر بردارهای دو بعدی.
\( \texttt{dst} (I) = \sqrt{\texttt{x}(I)^2 + \texttt{y}(I)^2} \)
تعریف تابع :
1 |
CV_EXPORTS_W void magnitude(InputArray x, InputArray y, OutputArray magnitude); |
توابع محاسبه مقدارهای ویژه ( eigenvalues ) و بردارهای ویژه ( eigenvectors ) یک ماتریس متقارن / نامتقارن :
1) تابع eigen : محاسبه مقدارهای ویژه ( eigenvalues ) و بردارهای ویژه ( eigenvectors ) یک ماتریس متقارن.
تعریف تابع :
1 |
CV_EXPORTS_W bool eigen(InputArray src, OutputArray eigenvalues, OutputArray eigenvectors = noArray()); |
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
2) تابع eigenNonSymmetric : محاسبه مقدارهای ویژه ( eigenvalues ) و بردارهای ویژه ( eigenvectors ) یک ماتریس نامتقارن.
تعریف تابع :
1 |
CV_EXPORTS_W void eigenNonSymmetric(InputArray src, OutputArray eigenvalues, OutputArray eigenvectors); |
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
توابع مرتبط با Border :
1) تابع borderInterpolate : مکان منبع یک پیکسل برون یابی ( extrapolated pixel ) را محاسبه میکند؛ این تابع مختصات یک پیکسل اهداکننده ( donor pixel ) متناظر با پیکسل برون یابی ( extrapolated pixel ) مشخص شده را با توجه به حالت مرزی برون یابی ( extrapolation border mode ) محاسبه میکند و برمیگرداند ( خلاصه اش میشه این که مختصات پیکسل های مجازی/حاشیه رو محاسبه میکنه و به کمک مختصات، مقدار پیکسل مجازی/حاشیه محاسبه میشه، چون پیکسل های مجازی/حاشیه به کمک پیکسل های واقعی تصویر مدنظر، محاسبه میشن )؛ برای مثال، اگر از حالت BORDER_WRAP در جهت افقی، و BORDER_REFLECT_101 در جهت عمودی استفاده میکنید و میخواهید مقدار پیکسل مجازی Point(-5، 100) را در یک تصویر اعشاری محاسبه کنید، به صورت زیر باید عمل کنید :
1 2 |
float val = img.at<float>(borderInterpolate(100, img.rows, cv::BORDER_REFLECT_101), borderInterpolate(-5, img.cols, cv::BORDER_WRAP)); |
به طور معمول، این تابع به طور مستقیم فراخوانی نمیشود؛ در داخل توابع فیلترها ( این مطلب : آموزش ماژول Image Filtering در OpenCV ) و همچنین در تابع copyMakeBorder ( همین مطلب ) استفاده میشود؛ فلذا عملا کاری با این تابع نداریم! مگه این که بخوایم یه فیلتر جدیدی ایجاد کنیم که...
تعریف تابع :
1 |
CV_EXPORTS_W int borderInterpolate(int p, int len, int borderType); |
توضیح پارامترها :
- p : مختصات پیکسل برون یابی ( extrapolated pixel ) در امتداد یکی از محورها، احتمالا \( p < 0 \) یا \( p >= len \)
- len : طول آرایه در امتداد محور مربوطه.
- borderType : این پارامتر به کمک نوع شمارشی cv::BorderTypes مقدار دهی میشه ( که در تابع copyMakeBorder تعریفشو قرار دادم، داخل کدهای OpenCV هم میتویند پیداش کنید )
2) تابع copyMakeBorder : یک حاشیه در اطراف تصویر ورودی ایجاد میکند.
تعریف تابع :
1 2 3 4 |
CV_EXPORTS_W void copyMakeBorder( InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar& value = Scalar() ); |
توضیح پارامترها :
src : تصویر ورودی.
dst : تصویر خروجی؛ نوع dst برابر با نوع src هستش، اما اندازه dst به صورت زیر محاسبه میشه :
1 |
Size(src.cols + left + right, src.rows + top + bottom) |
top و bottom و left و right : اندازه حاشیه در 4 گوشه تصویر، بر حسب پیکسل.
borderType : نوع حاشیه؛ به کمک نوع شماشی BorderTypes مقدار دهی میشه ( نوع BORDER_TRANSPARENT توسط تابع copyMakeBorder پشتیبانی نمیشه ) :
value : مقدار حاشیه، اگر borderType برابر با BORDER_CONSTANT و یا BORDER_ISOLATED باشد.
نوع شمارشی BorderTypes : خب اینجا با مقدار های BORDER_REFLECT101 و BORDER_DEFAULT که کاری نداریم ( دلیلش هم مشخصه! )؛ میمونه مقدار های BORDER_CONSTANT و BORDER_ISOLATED که یجورایی جفت / 2قلو!!! هستن ( یکیشونو باید انتخاب کنید!؛ توجه کنید که مقدار BORDER_CONSTANT برابر با 0 هستش و یعنی به صورت پیشفرض فعاله! ) مختصرا توضیح بدم : ایندو یکسان هستن، تنها فرقشون اینه که گزینه BORDER_ISOLATED نیم نگاهی به تصویر اصلی داره ( اگه تصویر ما یه ROI از تصویر اصلی باشه ) اما گزینه BORDER_CONSTANT اون نیم نگاه رو نداره! احتملا متوجه نشده باشید، زیاد مهم نی، توضیحات کامل رو در ادامه مطلب گفتم؛ میمونه بقیه مدها! هر کزینه روش محاسبه مجزایی داره که در زیر مشاهده میکنید ( که مثل یه خط کش فرض کنید که روی سطر و ستون و طوری که متوجه شدم، روی قطر ها میزارید و مقدار پیکسل های مجازی یا همون پیکسل های حاشیه رو محاسبه میکیند )؛ معمولا این گزینه ها ( BORDER_CONSTANT یا BORDER_ISOLATED ) رو با گزینه های دیگه AND بیتی میکنند؛ مثلا "BORDER_REPLICATE | BORDER_ISOLATED" یا "BORDER_REPLICATE | BORDER_CONSTANT" ( که معادل "BORDER_REPLICATE" هستش؛ AND بیتی هر داده ای با 0، میشه خودش! )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
enum BorderTypes { BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i` BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh` BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb` BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg` BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba` BORDER_TRANSPARENT = 5, //!< `uvwxyz|abcdefgh|ijklmno` BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101 BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101 BORDER_ISOLATED = 16 //!< do not look outside of ROI }; |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
void operations_on_arrays_example1::copyMakeBorder1_test() { /// Test all modes. /// BORDER_TRANSPARENT is not supported by copyMakeBorder function. float src_data[3][3] = { {1,2,3}, {4,5,6}, {7,8,9}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); cv::Mat dst_CONSTANT, dst_REPLICATE, dst_REFLECT, dst_WRAP, dst_REFLECT_101, dst_ISOLATED; cv::copyMakeBorder(src, dst_CONSTANT, 1, 1, 1, 1, cv::BorderTypes::BORDER_CONSTANT, cv::Scalar::all(255)); // `iiiiii|abcdefgh|iiiiiii` with some specified `i` cv::copyMakeBorder(src, dst_REPLICATE, 1, 1, 1, 1, cv::BorderTypes::BORDER_REPLICATE, cv::Scalar::all(255)); // `aaaaaa|abcdefgh|hhhhhhh` cv::copyMakeBorder(src, dst_REFLECT, 1, 1, 1, 1, cv::BorderTypes::BORDER_REFLECT, cv::Scalar::all(255)); // `fedcba|abcdefgh|hgfedcb` cv::copyMakeBorder(src, dst_WRAP, 1, 1, 1, 1, cv::BorderTypes::BORDER_WRAP, cv::Scalar::all(255)); // `cdefgh|abcdefgh|abcdefg` cv::copyMakeBorder(src, dst_REFLECT_101, 1, 1, 1, 1, cv::BorderTypes::BORDER_REFLECT_101, cv::Scalar::all(255)); // `gfedcb|abcdefgh|gfedcba` cv::copyMakeBorder(src, dst_ISOLATED, 1, 1, 1, 1, cv::BorderTypes::BORDER_ISOLATED, cv::Scalar::all(255)); // do not look outside of ROI std::cout << "src = \n" << src << std::endl; std::cout << "dst [ BORDER_CONSTANT ] = \n" << dst_CONSTANT << std::endl; std::cout << "dst [ BORDER_REPLICATE ] = \n" << dst_REPLICATE << std::endl; std::cout << "dst [ BORDER_REFLECT ] = \n" << dst_REFLECT << std::endl; std::cout << "dst [ BORDER_WRAP ] = \n" << dst_WRAP << std::endl; std::cout << "dst [ BORDER_REFLECT_101 ] = \n" << dst_REFLECT_101 << std::endl; std::cout << "dst [ BORDER_ISOLATED ] = \n" << dst_ISOLATED << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
src = [1, 2, 3; 4, 5, 6; 7, 8, 9] dst [ BORDER_CONSTANT ] = [255, 255, 255, 255, 255; 255, 1, 2, 3, 255; 255, 4, 5, 6, 255; 255, 7, 8, 9, 255; 255, 255, 255, 255, 255] dst [ BORDER_REPLICATE ] = [1, 1, 2, 3, 3; 1, 1, 2, 3, 3; 4, 4, 5, 6, 6; 7, 7, 8, 9, 9; 7, 7, 8, 9, 9] dst [ BORDER_REFLECT ] = [1, 1, 2, 3, 3; 1, 1, 2, 3, 3; 4, 4, 5, 6, 6; 7, 7, 8, 9, 9; 7, 7, 8, 9, 9] dst [ BORDER_WRAP ] = [9, 7, 8, 9, 7; 3, 1, 2, 3, 1; 6, 4, 5, 6, 4; 9, 7, 8, 9, 7; 3, 1, 2, 3, 1] dst [ BORDER_REFLECT_101 ] = [5, 4, 5, 6, 5; 2, 1, 2, 3, 2; 5, 4, 5, 6, 5; 8, 7, 8, 9, 8; 5, 4, 5, 6, 5] dst [ BORDER_ISOLATED ] = [255, 255, 255, 255, 255; 255, 1, 2, 3, 255; 255, 4, 5, 6, 255; 255, 7, 8, 9, 255; 255, 255, 255, 255, 255] |
خب در این نتیجه بنظر میاد که نتایج BORDER_CONSTANT با BORDER_ISOLATED یکسان هستند؛ در ادامه مثال هایی میزنم تا ببینید که ایندو یکسان نیستن و ببینید که، کجاها نتایجشون فرق میکنه.
فرق BORDER_CONSTANT با BORDER_ISOLATED : هنگامی که از مد BORDER_CONSTANT استفاده میکنید و تصویر منبع بخشی ( ROI ) از یک تصویر بزرگتر است، تابع سعی می کند از پیکسل های خارج از ROI برای تشکیل یک حاشیه استفاده کند، اگه پیکسل کم اومد ( مثال زیر رو ببینید ) که از مقدار ثابتی که تعیین کردید استفاده میکنه تابع؛ هنگامی که از مد BORDER_ISOLATED استفاده میکنید، تابع اصلا کاری نداره که تصویری که بهش میدیم ROI هستش، نیستش، میاد و از مقدار ثابتی که براش تعیین کردیم استفاده میکنه.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
void operations_on_arrays_example1::copyMakeBorder2_test() { /// BORDER_CONSTANT vs BORDER_ISOLATED float src_data[5][5] = { {10,11,12,13,14}, {15,16,17,18,19}, {20,21,22,23,24}, {25,26,27,28,29}, {30,31,32,33,34}, }; cv::Mat src = cv::Mat(5, 5, CV_32FC1, src_data); cv::Mat roi = src(cv::Rect(1,1,3,3)); cv::Mat dst_CONSTANT, dst_ISOLATED; cv::copyMakeBorder(roi, dst_CONSTANT, 2, 2, 2, 2, cv::BorderTypes::BORDER_CONSTANT, cv::Scalar::all(255)); cv::copyMakeBorder(roi, dst_ISOLATED, 2, 2, 2, 2, cv::BorderTypes::BORDER_ISOLATED, cv::Scalar::all(255)); std::cout << "src = \n" << src << std::endl; std::cout << "roi = \n" << roi << std::endl; std::cout << "dst [ BORDER_CONSTANT ] = \n" << dst_CONSTANT << std::endl; std::cout << "dst [ BORDER_ISOLATED ] = \n" << dst_ISOLATED << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
src = [10, 11, 12, 13, 14; 15, 16, 17, 18, 19; 20, 21, 22, 23, 24; 25, 26, 27, 28, 29; 30, 31, 32, 33, 34] roi = [16, 17, 18; 21, 22, 23; 26, 27, 28] dst [ BORDER_CONSTANT ] = [255, 255, 255, 255, 255, 255, 255; 255, 10, 11, 12, 13, 14, 255; 255, 15, 16, 17, 18, 19, 255; 255, 20, 21, 22, 23, 24, 255; 255, 25, 26, 27, 28, 29, 255; 255, 30, 31, 32, 33, 34, 255; 255, 255, 255, 255, 255, 255, 255] dst [ BORDER_ISOLATED ] = [255, 255, 255, 255, 255, 255, 255; 255, 255, 255, 255, 255, 255, 255; 255, 255, 16, 17, 18, 255, 255; 255, 255, 21, 22, 23, 255, 255; 255, 255, 26, 27, 28, 255, 255; 255, 255, 255, 255, 255, 255, 255; 255, 255, 255, 255, 255, 255, 255] |
ایجاد حاشیه شفاف به کمک تابع copyMakeBorder : همونطور که پیشتر گفتم، نوع BORDER_TRANSPARENT توسط تابع copyMakeBorder پشتیبانی نمیشه؛ اما اگه میخواید حاشیه TRANSPARENT ایجاد کنید، میتویند از روش زیر استفاده کنید :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void operations_on_arrays_example1::copyMakeBorder3_test() { /// TRANSPARENT border with copyMakeBorder !!! cv::Mat src = cv::imread("C:/Users/Mahdi/Desktop/w10.jpg"); cv::cvtColor(src, src, cv::COLOR_BGR2BGRA); cv::Mat dst; cv::copyMakeBorder(src, dst, 10, 10, 10, 10, cv::BorderTypes::BORDER_CONSTANT, cv::Scalar(0, 0, 0, 0)); cv::imwrite("C:/Users/Mahdi/Desktop/dst.png", dst); } |
یه تصویر رنگی به تابع فوق میدید، فرمت رنگ رو از BGR به BGRA تغییر میدیم ( به کمک کانال ALPHA یا مختصرا A، میتونیم شفافیت پیکسل ها رو تنظیم کنیم )؛ بعد از حاشیه نوع BORDER_CONSTANT استفاده میکنیم تا بتونیم مقدار حاشیه رو خودمون تعیین کنیم، مقدار رو هم هرچی تنظیم کردید، کردید! فقط مقدار آخریش که مربوطه به کانال آلفا هستش رو 0 تنظیم کنید؛ موقعی هم که میخواید تصویر رو ذخیره کنید، حتما با فرمت PNG ذخیره کنید که از BGRA پشتیبانی میکنه ( فرمت JPG از BGRA پشتیبانی نمیکنه و نمیتونید تصویر شفاف با فرمت JPG ایجاد کنید )؛ بعد تصاویر رو که تو فوتوشاپ باز کنید، میتونید به راحتی حاشیه های شفاف ایجاد شده رو مشاهده کنید.
1 |
cv::Scalar( Blue Channel, Green Channel, Red Channel, Alpha Channel ) |
نتیجه کد بالا :
میتونید کارایی که در بالا کردم رو، روی تصاویر انجام بدید، نتیجه جالب باید باشه!
مطالعه بیشتر :
?????????????????????
1) تابع sort :
تعریف تابع :
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
2) تابع sortIdx :
تعریف تابع :
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
توابع مرتبط با ماتریس ها :
1) تابع determinant : محاسبه دترمینان ( determinant ) یک ماتریس مربعی اعشاری.
تعریف تابع :
1 |
CV_EXPORTS_W double determinant(InputArray mtx); |
توضیح پارامترها : ماتریس ورودی باید نوعش CV_32FC1 و یا CV_64FC1 و اندازش هم مربعی باشه.
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void operations_on_arrays_example1::determinant_test() { float src_data[3][3] = { {1,2,3}, {4,5,6}, {7,8,9}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); double result = cv::determinant(src); std::cout << "result = " << result << std::endl; // result = 0 } |
2) تابع invert : معکوس ( inverse ) یا شبه معکوس ( pseudo-inverse matrix ) یک ماتریس را پیدا میکند.
تعریف تابع :
1 |
CV_EXPORTS_W double invert(InputArray src, OutputArray dst, int flags = DECOMP_LU); |
توضیح پارامترها : پارامتر flags به کمک Enum زیر مقدار دهی میشه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
enum DecompTypes { /** Gaussian elimination with the optimal pivot element chosen. */ DECOMP_LU = 0, /** singular value decomposition (SVD) method; the system can be over-defined and/or the matrix src1 can be singular */ DECOMP_SVD = 1, /** eigenvalue decomposition; the matrix src1 must be symmetrical */ DECOMP_EIG = 2, /** Cholesky \f$LL^T\f$ factorization; the matrix src1 must be symmetrical and positively defined */ DECOMP_CHOLESKY = 3, /** QR factorization; the system can be over-defined and/or the matrix src1 can be singular */ DECOMP_QR = 4, /** while all the previous flags are mutually exclusive, this flag can be used together with any of the previous; it means that the normal equations \f$\texttt{src1}^T\cdot\texttt{src1}\cdot\texttt{dst}=\texttt{src1}^T\texttt{src2}\f$ are solved instead of the original system \f$\texttt{src1}\cdot\texttt{dst}=\texttt{src2}\f$ */ DECOMP_NORMAL = 16 }; |
3.1) تابع transpose : محاسبه ترانهاده ( Transpose ) یک ماتریس.
تعریف تابع :
1 |
CV_EXPORTS_W void transpose(InputArray src, OutputArray dst); |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void operations_on_arrays_example1::transpose_test() { float src_data[3][2] = { {1,2}, {3,4}, {5,6}, }; cv::Mat src = cv::Mat(3, 2, CV_32FC1, src_data); cv::Mat dst; cv::transpose(src, dst); std::cout << "src = " << std::endl << src << std::endl; std::cout << "dst = " << std::endl << dst << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 6 7 |
src = [1, 2; 3, 4; 5, 6] dst = [1, 3, 5; 2, 4, 6] |
3.3) تابع mulTransposed : -
\( \texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} )^T ( \texttt{src} - \texttt{delta} ) \)
اگر aTa = true :
\( \texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} ) ( \texttt{src} - \texttt{delta} )^T \)
تعریف تابع :
1 2 3 4 5 6 7 |
CV_EXPORTS_W void mulTransposed( InputArray src, OutputArray dst, bool aTa, InputArray delta = noArray(), double scale = 1, int dtype = -1 ); |
4) تابع trace : محاسبه اثر ماتریس ( trace of matrix )؛ این تابع، مجموع عناصر قطری ماتریس mtx را برمی گرداند.
\( \mathrm{tr} ( \texttt{mtx} ) = \sum _i \texttt{mtx} (i,i) \)
تعریف تابع :
1 |
CV_EXPORTS_W Scalar trace(InputArray mtx); |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void operations_on_arrays_example1::trace_test() { float src_data[3][3] = { {1,2,3}, {4,5,6}, {7,8,9}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); cv::Scalar result = cv::trace(src); std::cout << "src = " << std::endl << src << std::endl; std::cout << "result = " << result << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 |
src = [1, 2, 3; 4, 5, 6; 7, 8, 9] result = [15, 0, 0, 0] |
5) تابع sum : مجموع عناصر آرایه به طور مستقل برای هر کانال محاسبه میکند.
تعریف تابع :
1 |
CV_EXPORTS_AS(sumElems) Scalar sum(InputArray src); |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void operations_on_arrays_example1::sum_test() { float src_data[3][3] = { {1,2,3}, {4,5,6}, {7,8,9}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); cv::Scalar result = cv::sum(src); std::cout << "src = " << std::endl << src << std::endl; std::cout << "result = " << result << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 |
src = [1, 2, 3; 4, 5, 6; 7, 8, 9] result = [45, 0, 0, 0] |
6) تابع rotate : یک آرایه دو بعدی را در مضربی از 90 درجه می چرخاند.
تعریف تابع :
1 |
CV_EXPORTS_W void rotate(InputArray src, OutputArray dst, int rotateCode); |
توضیح پارامترها : پارامتر rotateCode به کمک enum زیر مقدار دهی میشود :
1 2 3 4 5 6 |
enum RotateFlags { ROTATE_90_CLOCKWISE = 0, //!<Rotate 90 degrees clockwise ROTATE_180 = 1, //!<Rotate 180 degrees clockwise ROTATE_90_COUNTERCLOCKWISE = 2, //!<Rotate 270 degrees clockwise }; |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
void operations_on_arrays_example1::rotate_test() { float src_data[3][3] = { {1,2,3}, {4,5,6}, {7,8,9}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); cv::Mat dst1, dst2, dst3; cv::rotate(src, dst1, cv::RotateFlags::ROTATE_90_CLOCKWISE); cv::rotate(src, dst2, cv::RotateFlags::ROTATE_90_COUNTERCLOCKWISE); cv::rotate(src, dst3, cv::RotateFlags::ROTATE_180); std::cout << "src = " << std::endl << src << std::endl; std::cout << "dst1 = " << std::endl << dst1 << std::endl; std::cout << "dst2 = " << std::endl << dst2 << std::endl; std::cout << "dst3 = " << std::endl << dst2 << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
src = [1, 2, 3; 4, 5, 6; 7, 8, 9] dst1 = [7, 4, 1; 8, 5, 2; 9, 6, 3] dst2 = [3, 6, 9; 2, 5, 8; 1, 4, 7] dst3 = [3, 6, 9; 2, 5, 8; 1, 4, 7] |
7.1) تابع countNonZero : شمارش تعداد عناصر غیر صفر آرایه ورودی.
تعریف تابع :
1 |
CV_EXPORTS_W int countNonZero( InputArray src ); |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void operations_on_arrays_example1::countNonZero_test() { float src_data[3][3] = { {0,2,0}, {4,0,6}, {0,8,0}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); int result = cv::countNonZero(src); std::cout << "result = " << result << std::endl; // result = 4 } |
7.2) تابع findNonZero : لیست مکان پیکسل های غیر صفر را برمی گرداند.
تعریف تابع :
1 |
CV_EXPORTS_W void findNonZero( InputArray src, OutputArray idx ); |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void operations_on_arrays_example1::findNonZero_test() { float src_data[3][3] = { {0,2,0}, {4,0,6}, {0,8,0}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); cv::Mat dst; //std::vector<cv::Point> dst; cv::findNonZero(src, dst); std::cout << "src = " << std::endl << src << std::endl; std::cout << "dst = " << std::endl << dst << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 6 7 8 9 |
src = [0, 2, 0; 4, 0, 6; 0, 8, 0] dst = [1, 0; 0, 1; 2, 1; 1, 2] |
8) تابع flip : یک آرایه دو بعدی را حول محورهای عمودی، افقی یا هر دو می چرخاند.
تعریف تابع :
1 |
CV_EXPORTS_W void flip(InputArray src, OutputArray dst, int flipCode); |
توضیح پارامترها : چرخش آرایه حول محور X ( flipCode = 0 )؛ چرخش آرایه حول محور Y ( flipCode > 0 )؛ چرخش آرایه حول محورهای X و Y ( flipCode < 0 ).
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
void operations_on_arrays_example1::flip_test() { float src_data[3][3] = { {1,2,3}, {4,5,6}, {7,8,9}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); cv::Mat dst1, dst2, dst3; cv::flip(src, dst1, 0); // X cv::flip(src, dst2, +1); // Y cv::flip(src, dst3, -1); // X+Y std::cout << "src = " << std::endl << src << std::endl; std::cout << "dst1 = " << std::endl << dst1 << std::endl; std::cout << "dst2 = " << std::endl << dst2 << std::endl; std::cout << "dst3 = " << std::endl << dst3 << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
src = [1, 2, 3; 4, 5, 6; 7, 8, 9] dst1 = [7, 8, 9; 4, 5, 6; 1, 2, 3] dst2 = [3, 2, 1; 6, 5, 4; 9, 8, 7] dst3 = [9, 8, 7; 6, 5, 4; 3, 2, 1] |
9) تابع setIdentity : یک ماتریس همانی ( Identity Matrix ) مقیاس شده را راه اندازی ( مقدار دهی اولیه ) میکنه؛ تو ماتریس همانی، عناصر روی قطر اصلی ماتریس، 1 و بقیه عناصر 0 هستند ولی این تابع میگه ماتریس همانی مقیاس شده فلذا دیگه اون عناصر 1 نیستند و هرچی در پارامتر s در تابع setIdentity تنظیم کنید، خواهند بود.
\( \text{mtx} (i,j) = \begin{cases} \text{value} & \text{if $i$=$j$} \\ 0 & \text{otherwise} \end{cases} \)
تعریف تابع :
1 |
CV_EXPORTS_W void setIdentity(InputOutputArray mtx, const Scalar& s = Scalar(1)); |
کد نمونه :
1 2 3 4 5 6 7 8 |
void operations_on_arrays_example1::setIdentity_test() { cv::Mat mtx = cv::Mat(3, 4, CV_32FC1); cv::setIdentity(mtx, cv::Scalar(5)); std::cout << "mtx = " << std::endl << mtx << std::endl; } |
نتیجه کد بالا :
1 2 3 4 |
mtx = [5, 0, 0, 0; 0, 5, 0, 0; 0, 0, 5, 0] |
10.1) تابع reduce : یک ماتریس را به بردار کاهش میدهد؛ تابع reduce با در نظر گرفتن سطرها/ستون های ماتریس به عنوان مجموعه ای از بردارهای 1 بعدی و انجام عملیات مشخص شده روی بردارها تا زمانی که یک سطر/ستون واحد به دست آید، ماتریس را به یک بردار کاهش میدهد؛ به عنوان مثال، تابع را میتوان برای محاسبه پیش بینی های افقی و عمودی یک تصویر شطرنجی استفاده کرد؛ در مورد REDUCE_MAX و REDUCE_MIN، نوع dst باید همانند نوع src باشد؛ در مورد REDUCE_SUM و REDUCE_AVG، نوع dst ممکن است عمق بیتی ( bit-depth ) بزرگتری برای حفظ دقت داشته باشد؛ آرایه های چند کانالی نیز در این دو حالت کاهش پشتیبانی میشوند.
تعریف تابع :
1 |
CV_EXPORTS_W void reduce(InputArray src, OutputArray dst, int dim, int rtype, int dtype = -1); |
توضیح پارامترها :
- src : ماتریس 2 بعدی.
- dst : بردار خروجی؛ با اندازه ای برابر با ( مقدار تعیین شده در پارامتر ) dim و نوعی برابر با ( مقدار تعیین شده در پارامتر ) dtype.
- dim : شاخص ابعادی که در طول آن ماتریس کاهش مییابد؛ 0 به این معنی است که ماتریس به یک ردیف کاهش مییابد؛ 1 به این معنی است که ماتریس به یک ستون کاهش مییابد.
- rtype : عملیات کاهش که به کمک enum زیر مقداردهی میشود.
- dtype : زمانی که مقدارش منفی باشه، نوع dst برابر با src خواهد بود، در غیر اینصورت مقداری که در این پارامتر تنظیم میکنید، نوع dst رو تعیین میکنه.
1 2 3 4 5 6 7 |
enum ReduceTypes { REDUCE_SUM = 0, //!< the output is the sum of all rows/columns of the matrix. REDUCE_AVG = 1, //!< the output is the mean vector of all rows/columns of the matrix. REDUCE_MAX = 2, //!< the output is the maximum (column/row-wise) of all rows/columns of the matrix. REDUCE_MIN = 3 //!< the output is the minimum (column/row-wise) of all rows/columns of the matrix. }; |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
void operations_on_arrays_example1::reduce_test() { float src_data[3][3] = { {1,2,3}, {4,5,6}, {7,8,9}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); cv::Mat dst_col_avg, dst_col_max, dst_col_min, dst_col_sum; cv::Mat dst_row_avg, dst_row_max, dst_row_min, dst_row_sum; std::cout << "src = \n" << src << std::endl; cv::reduce(src, dst_col_avg, 0, cv::ReduceTypes::REDUCE_AVG, CV_64F); std::cout << "dst_col_avg = \n" << dst_col_avg << std::endl; cv::reduce(src, dst_col_max, 0, cv::ReduceTypes::REDUCE_MAX, src.depth()); std::cout << "dst_col_max = \n" << dst_col_max << std::endl; cv::reduce(src, dst_col_min, 0, cv::ReduceTypes::REDUCE_MIN, src.depth()); std::cout << "dst_col_min = \n" << dst_col_min << std::endl; cv::reduce(src, dst_col_sum, 0, cv::ReduceTypes::REDUCE_SUM, CV_64F); std::cout << "dst_col_sum = \n" << dst_col_sum << std::endl; cv::reduce(src, dst_row_avg, 1, cv::ReduceTypes::REDUCE_AVG, CV_64F); std::cout << "dst_row_avg = \n" << dst_row_avg << std::endl; cv::reduce(src, dst_row_max, 1, cv::ReduceTypes::REDUCE_MAX, src.depth()); std::cout << "dst_row_max = \n" << dst_row_max << std::endl; cv::reduce(src, dst_row_min, 1, cv::ReduceTypes::REDUCE_MIN, src.depth()); std::cout << "dst_row_min = \n" << dst_row_min << std::endl; cv::reduce(src, dst_row_sum, 1, cv::ReduceTypes::REDUCE_SUM, CV_64F); std::cout << "dst_row_sum = \n" << dst_row_sum << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
src = [1, 2, 3; 4, 5, 6; 7, 8, 9] dst_col_avg = [4, 5, 6] dst_col_max = [7, 8, 9] dst_col_min = [1, 2, 3] dst_col_sum = [12, 15, 18] dst_row_avg = [2; 5; 8] dst_row_max = [3; 6; 9] dst_row_min = [1; 4; 7] dst_row_sum = [6; 15; 24] |
توجه : در مسیر زیر هم کد نمونه مشابهی نیز وجود داره :
[opencv-4.6.0]/samples/cpp/tutorial_code/snippets/core_reduce.cpp
10.2) تابع reduceArgMax : -
تعریف تابع :
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
10.3) تابع reduceArgMin : -
تعریف تابع :
توضیح پارامترها :
کد نمونه :
نتیجه کد بالا :
11) تابع inRange : این تابع بررسی میکنه که عناصر آرایه ورودی، بین عناصر دو آرایه ( یا مقدار ثابت Scalar ) lowerb و upperb هستند یا نه؛ اگر قرار داشتند که مقدار اون عنصر در آرایه خروجی 255 میشه وگرنه 0 میشه.
برای هر عنصر از یک آرایه ورودی تک کاناله :
\( \text{dst} (I)= \text{lowerb} (I)_0 \leq \text{src} (I)_0 \leq \text{upperb} (I)_0 \)
برای آرایه های دو کاناله : نماد \( \land \) به معنی AND هستش.
\( \text{dst} (I)= \text{lowerb} (I)_0 \leq \text{src} (I)_0 \leq \text{upperb} (I)_0 \land \text{lowerb} (I)_1 \leq \text{src} (I)_1 \leq \text{upperb} (I)_1 \)
و...
تعریف تابع :
1 2 3 4 5 |
CV_EXPORTS_W void inRange( InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst ); |
توضیح پارامترها :
- src : آرایه ورودی.
- lowerb : آرایه حاوی مرز پایین یا یک مقدار ثابت Scalar.
- upperb : آرایه حاوی مرز بالا یا یک مقدار ثابت Scalar.
- dst : آرایه خروجی؛ با اندازه ای برابر با src و نوع CV_8U.
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void operations_on_arrays_example1::inRange_test() { uchar src_data[5][5] = { {10,11,12,13,14}, {15,16,17,18,19}, {20,21,22,23,24}, {25,26,27,28,29}, {30,31,32,33,34}, }; cv::Mat src = cv::Mat(5, 5, CV_8UC1, src_data); cv::Mat dst; cv::inRange(src, cv::Scalar(12), cv::Scalar(32), dst); std::cout << "src = \n" << src << std::endl; std::cout << "dst = \n" << dst << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 6 7 8 9 10 11 12 |
src = [ 10, 11, 12, 13, 14; 15, 16, 17, 18, 19; 20, 21, 22, 23, 24; 25, 26, 27, 28, 29; 30, 31, 32, 33, 34] dst = [ 0, 0, 255, 255, 255; 255, 255, 255, 255, 255; 255, 255, 255, 255, 255; 255, 255, 255, 255, 255; 255, 255, 255, 0, 0] |
مطلب مرتبط با این تابع : Thresholding Operations using inRange
12) تابع patchNaNs : تبدیل مقادیر NAN به مقدار مدنظر.
تعریف تابع :
1 |
CV_EXPORTS_W void patchNaNs(InputOutputArray a, double val = 0); |
توضیح پارامترها : ماتریس ورودی / خروجی a باید از نوع CV_32F باشد.
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void operations_on_arrays_example1::patchNaNs_test() { // INFINITY = (float)(1e+300 * 1e+300) ---> must overflow // NAN = (float)(INFINITY * 0.0F) float src_data[3][3] = { {1,2,3}, {4,5,NAN}, {7,8,INFINITY}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); std::cout << "src before patchNaNs = \n" << src << std::endl; cv::patchNaNs(src, 13); std::cout << "src after patchNaNs = \n" << src << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 6 7 8 |
src before patchNaNs = [1, 2, 3; 4, 5, -nan(ind); 7, 8, inf] src after patchNaNs = [1, 2, 3; 4, 5, 13; 7, 8, inf] |
13.1) تابع mean : میانگین ( average / mean ) عناصر یک آرایه را محاسبه میکند؛ محاسبات برای هر کانال، به صورت مستقل انجام میگیرد.
تعریف تابع :
1 |
CV_EXPORTS_W Scalar mean(InputArray src, InputArray mask = noArray()); |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void operations_on_arrays_example1::mean_test() { float src_data[3][3] = { {1,2,3}, {4,5,6}, {7,8,9}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); cv::Scalar avg = cv::mean(src); std::cout << "Average [ mean ] = " << avg << std::endl; // Average [ mean ] = [5, 0, 0, 0] } |
محاسبه میانگین رنگ در OpenCV : برای اینکار از تابع mean استفاده میکنیم و محدوده ای که میخوایم میانگین رنگشو محاسبه کنیم، ماسک شو ایجاد میکنیم و به تابع mean میدیم؛ در کد زیر میانگین رنگ هر محدوده 50x50 پیکسل عکس رو پیدا کردم و جایگزین پیکسل ها کردم :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" const int TILE_SIZE = 50; // height/width of mosaic tiles in pixels int main() { cv::Mat src = cv::imread("C:/Users/Mahdi/Desktop/image.jpg"); cv::Mat dst = src.clone(); for(int r = 0; r < src.rows; r+=TILE_SIZE) { for(int c = 0; c < src.cols; c+=TILE_SIZE) { std::vector<cv::Point> points; //--- int newC = ((c + TILE_SIZE) > (src.cols - 1)) ? (src.cols - 1) : (c + TILE_SIZE); int newR = ((r + TILE_SIZE) > (src.rows - 1)) ? (src.rows - 1) : (r + TILE_SIZE); //--- points.push_back(cv::Point(c, r)); points.push_back(cv::Point(newC, r)); points.push_back(cv::Point(newC, newR)); points.push_back(cv::Point(c, newR)); /// The average color of the corresponding area // Create the mask with the polygon cv::Mat mask(src.rows, src.cols, CV_8UC1, cv::Scalar::all(0)); cv::fillPoly(mask, points, cv::Scalar::all(255)); // Compute the mean with the computed mask cv::Scalar color = cv::mean(src, mask); // draw cv::fillConvexPoly(dst, points, color, cv::LINE_AA); } } cv::imshow("src", src); cv::imshow("dst", dst); cv::waitKey(); return 0; } |
نتیجه کد بالا :
13.2) تابع meanStdDev : میانگین ( average / mean ) و انحراف معیار ( standard deviation ) عناصر آرایه را محاسبه میکند؛ محاسبات برای هر کانال، به صورت مستقل انجام میگیرد.
تعریف تابع :
1 |
CV_EXPORTS_W void meanStdDev(InputArray src, OutputArray mean, OutputArray stddev, InputArray mask=noArray()); |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void operations_on_arrays_example1::meanStdDev_test() { float src_data[3][3] = { {1,2,3}, {4,5,6}, {7,8,9}, }; cv::Mat src = cv::Mat(3, 3, CV_32FC1, src_data); //cv::Mat mean, sDev; cv::Scalar mean, sDev; cv::meanStdDev(src, mean, sDev); std::cout << "mean = " << mean << std::endl; // mean = [5, 0, 0, 0] std::cout << "sDev = " << sDev << std::endl; // sDev = [2.58199, 0, 0, 0] } |
14) تابع compare : مقایسه عناصر دو آرایه یا یک آرایه و مقدار اسکالر را انجام میدهد؛ هنگامی که نتیجه مقایسه درست باشد، عنصر مربوطه در آرایه خروجی روی 255 تنظیم میشود، در غیر اینصورت 0 تنظیم میشود؛ مثلا مقایسه 2 آرایه رو روی مد CMP_EQ تنظیم کردید، حالا هر جایی که عناصر دو آرایه با هم برابر باشن، اون خونه در آرایه خروجی، مقدارش 255 میشه و اگه برابر نبودن که 0 میشه و...
تعریف تابع :
1 |
CV_EXPORTS_W void compare(InputArray src1, InputArray src2, OutputArray dst, int cmpop); |
توضیح پارامترها : پارامتر cmpop به کمک enum زیر مقدار دهی میشه.
1 2 3 4 5 6 7 8 9 |
enum CmpTypes { CMP_EQ = 0, //!< src1 is equal to src2. CMP_GT = 1, //!< src1 is greater than src2. CMP_GE = 2, //!< src1 is greater than or equal to src2. CMP_LT = 3, //!< src1 is less than src2. CMP_LE = 4, //!< src1 is less than or equal to src2. CMP_NE = 5 //!< src1 is unequal to src2. }; |
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
void operations_on_arrays_example1::compare_test() { float src_data[3][3] = { {1,2,3}, {4,5,6}, {7,8,9}, }; cv::Mat src1 = cv::Mat(3, 3, CV_32FC1, src_data); cv::Mat dst1, dst2, dst3, dst4, dst5, dst6; cv::compare(src1, cv::Scalar(3), dst1, cv::CmpTypes::CMP_EQ); // CMP_EQ : src1 is equal to src2. cv::compare(src1, cv::Scalar(3), dst2, cv::CmpTypes::CMP_GT); // CMP_GT : src1 is greater than src2. cv::compare(src1, cv::Scalar(3), dst3, cv::CmpTypes::CMP_GE); // CMP_GE : src1 is greater than or equal to src2. cv::compare(src1, cv::Scalar(3), dst4, cv::CmpTypes::CMP_LT); // CMP_LT : src1 is less than src2. cv::compare(src1, cv::Scalar(3), dst5, cv::CmpTypes::CMP_LE); // CMP_LE : src1 is less than or equal to src2. cv::compare(src1, cv::Scalar(3), dst6, cv::CmpTypes::CMP_NE); // CMP_NE : src1 is unequal to src2. std::cout << "src1 = \n" << src1 << std::endl; std::cout << "src2 = \n" << cv::Scalar(3) << std::endl; //--- std::cout << "dst1 = \n" << dst1 << std::endl; std::cout << "dst2 = \n" << dst2 << std::endl; std::cout << "dst3 = \n" << dst3 << std::endl; std::cout << "dst4 = \n" << dst4 << std::endl; std::cout << "dst5 = \n" << dst5 << std::endl; std::cout << "dst6 = \n" << dst6 << std::endl; } |
نتیجه کد بالا :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
src1 = [1, 2, 3; 4, 5, 6; 7, 8, 9] src2 = [3, 0, 0, 0] dst1 = [ 0, 0, 255; 0, 0, 0; 0, 0, 0] dst2 = [ 0, 0, 0; 255, 255, 255; 255, 255, 255] dst3 = [ 0, 0, 255; 255, 255, 255; 255, 255, 255] dst4 = [255, 255, 0; 0, 0, 0; 0, 0, 0] dst5 = [255, 255, 255; 0, 0, 0; 0, 0, 0] dst6 = [255, 255, 0; 255, 255, 255; 255, 255, 255] |
15) تابع calcCovarMatrix : ماتریس کوواریانس ( Covariance Matrix ) مجموعه ای از بردارها را محاسبه میکند؛ این تابع علاوه بر محاسبه ماتریس کوواریانس، به صورت اختیاری، میانگین بردار ( mean vector ) مجموعه بردارهای ورودی را نیز محاسبه میکند.
تعریف تابع :
1 2 3 4 5 6 |
CV_EXPORTS_W void calcCovarMatrix( InputArray samples, OutputArray covar, InputOutputArray mean, int flags, int ctype = CV_64F ); |
توضیح پارامترها : پارامتر CovarFlags به کمک enum زیر مقدار دهی میشه.
1 2 3 4 5 6 7 8 9 |
enum CovarFlags { COVAR_SCRAMBLED = 0, COVAR_NORMAL = 1, COVAR_USE_AVG = 2, COVAR_SCALE = 4, COVAR_ROWS = 8, COVAR_COLS = 16 }; |
کد نمونه :
نتیجه کد بالا :
16) تابع LUT : تبدیل جدول جستجو ( look-up table transform ) را برای آرایه ورودی انجام میدهد؛ این تابع، آرایه خروجی را با مقادیر جدول جستجو پر میکند.
\( \texttt{dst} (I) \leftarrow \texttt{lut(src(I) + d)} \)
\( d = \begin{cases} 0 & \text{if src has depth CV_8U} \\ 128 & \text{if src has depth CV_8S} \end{cases} \)
تعریف تابع :
1 |
CV_EXPORTS_W void LUT(InputArray src, InputArray lut, OutputArray dst); |
کد نمونه : 3 نوع مثال زدم برا این تابع، فک کنم کافی باشه برا فهمیدن کار این تابع.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
void operations_on_arrays_example1::LUT_test() { cv::Mat src = cv::imread("C:/Users/Mahdi/Desktop/w10.jpg"); cv::Mat dst1, dst2_1, dst2_2, dst3_1, dst3_2; // 1) Reduce the number of colors uchar lut_data1[256]; int divideWith = 50; for (int i = 0; i < 256; i++) { lut_data1[i] = (uchar)(divideWith * (i/divideWith)); } cv::Mat lut1 = cv::Mat(1, 256, CV_8UC1, lut_data1); // 2) invert color, work like this code : // cv::bitwise_not(src, dst); uchar lut_data2[256]; for (int i = 0; i < 256; i++) { lut_data2[i] = (uchar)(255-i); } cv::Mat lut2 = cv::Mat(1, 256, CV_8UC1, lut_data2); // 3) change range, work like this code : // cv::normalize(src, dst2, 100, 150, cv::NormTypes::NORM_MINMAX); uchar lut_data3[256]; //--- int OldMin = 0, OldMax = 255; int OldRange = OldMax - OldMin; int NewMin = 100, NewMax = 150; int NewRange = NewMax - NewMin; //--- for (int i = 0; i < 256; i++) { int OldValue = i; int NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin; lut_data3[i] = NewValue; } cv::Mat lut3 = cv::Mat(1, 256, CV_8UC1, lut_data3); cv::LUT(src, lut1, dst1); //--- cv::LUT(src, lut2, dst2_1); cv::bitwise_not(src, dst2_2); //--- cv::LUT(src, lut3, dst3_1); cv::normalize(src, dst3_2, 100, 150, cv::NormTypes::NORM_MINMAX); cv::imshow("src", src); //--- cv::imshow("dst1", dst1); //--- cv::imshow("dst2_1", dst2_1); cv::imshow("dst2_2", dst2_2); //--- cv::imshow("dst3_1", dst3_1); cv::imshow("dst3_2", dst3_2); } |
نتیجه کد بالا :
فایل خام تصویر ورودی :
تصاویر خروجی :
مطالعه بیشتر :
17.1) تابع min : محاسبه minimum عناصر دو آرایه یا یک آرایه و یک اسکالر.
\( \texttt{dst} (I)= \min ( \texttt{src1} (I), \texttt{src2} (I)) \)
\( \texttt{dst} (I)= \min ( \texttt{src1} (I), \texttt{value} ) \)
تعریف توابع :
1 2 3 |
CV_EXPORTS_W void min(InputArray src1, InputArray src2, OutputArray dst); CV_EXPORTS void min(const Mat& src1, const Mat& src2, Mat& dst); CV_EXPORTS void min(const UMat& src1, const UMat& src2, UMat& dst); |
17.2) تابع max : محاسبه maximum عناصر دو آرایه یا یک آرایه و یک اسکالر.
\( \texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{src2} (I)) \)
\( \texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{value} ) \)
تعریف توابع :
1 2 3 |
CV_EXPORTS_W void max(InputArray src1, InputArray src2, OutputArray dst); CV_EXPORTS void max(const Mat& src1, const Mat& src2, Mat& dst); CV_EXPORTS void max(const UMat& src1, const UMat& src2, UMat& dst); |
18.1) تابع perspectiveTransform : اعمال تبدیل perspective به آرایه ورودی؛ در مطلب ( آموزش ماژول Geometric Image Transformations در OpenCV )، با تابع warpPerspective آشنا شدیم، که عملکردش با تابع perspectiveTransform یکسان بنظر میرسه؛ فرقشون در اینه که warpPerspective برای تصاویر عمل میکرد و perspectiveTransform برای بردارها ( به نقل از : What is the difference between warpPerspective and perspectiveTransform )
تعریف تابع :
1 |
CV_EXPORTS_W void perspectiveTransform(InputArray src, OutputArray dst, InputArray m ); |
توضیح پارامترها :
- src : آرایه ورودی 2 یا 3 کاناله اعشاری؛ هر عنصر یک بردار 2_بعدی / 3_بعدی است که باید تبدیل شود.
- dst : آرایه خروجی؛ با اندازه و نوعی برابر با src.
- m : ماتریس تبدیل اعشاری 3x3 یا 4x4.
کد نمونه : در مسیرهای زیر، مثالهایی از این تابع رو مشاهده میکنید :
[opencv]/samples/cpp/asift.cpp
[opencv]/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp
[opencv]/samples/cpp/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.cpp
18.2) تابع transform : -
تعریف تابع :
1 |
CV_EXPORTS_W void transform(InputArray src, OutputArray dst, InputArray m ); |
19) تابع repeat : آرایه خروجی را با کپی های مکرر از آرایه ورودی، در امتداد هر یک از دو محور، پر میکند.
تعریف توابع :
1 2 |
CV_EXPORTS_W void repeat(InputArray src, int ny, int nx, OutputArray dst); CV_EXPORTS Mat repeat(const Mat& src, int ny, int nx); |
توضیح پارامترها :
- src : آرایه ورودی.
- dst : آرایه خروجی؛ با نوعی برابر با src.
- nx : تعداد تکرار در امتداد محور افقی ( X ).
- ny : تعداد تکرار در امتداد محور عمودی( Y ).
کد نمونه :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void operations_on_arrays_example1::repeat_test() { float src_data[2][2] = { {1,2}, {3,4}, }; cv::Mat src = cv::Mat(2, 2, CV_32FC1, src_data); cv::Mat dst; cv::repeat(src, 2, 3, dst); std::cout << "src = \n" << src << std::endl; std::cout << "dst = \n" << dst << std::endl; } |
نتیجه کد بالا :
1 2 |