مرحله اول پیش پردازش هستش. چون تصاویر قرار داده شده خیلی کوچیکه در ابتدا بایستی تصاویر فوق را Upsample کنید تا جزئیات در آبجکت هایی که خورده شده مشخص باشه در مرحله بعد چون آبجکت های شما سیاه هستش باید تصویر را not کنید چون در پردازش تصویر قرار داد کردیم که آبجکت ها به صورت سفید پردازش بشن و در انتها فیلتر median را بر روی تصویر اعمال می کنیم تا نویزهای احتمالی کاهش پیدا کنند.برای آستانه گیری هم از روش Otsu استفاده می کنیم چون مقادیر آستانه به صورت بهینه محاسبه میشه بر روی ماسک بدست آمده به انداره 5*5 فیلتر گوسین اعمال می کینم و مجدداً آستانه گیری می کنیم تا لبه های کاملاً صافی داشته باشیم.حالا بلاب های ما آماده شده برای عملیات پردازش.
مرحله دوم در ابتدا مرکز ثقل هر یک از آبجکتها(بلاب ها) مذکور را بدست آورده و سپس کانتور خارجی هر یک از آبجکت ها را بدست بیارید.سپس برای هر نقطه از کانتور فاصله آن نقطه تا مرکز آبجکت را محاسبه کنید مجموعه ای از این فواصل را برای هریک از آبجکت ها محاسبه کرده و در یک vector از نوع float میریزیم چون قصد داریم این داده های بدست آمده را مشتق بگیریم چون مشتق مقادیریش اعشاری میشه .سپس vetcor را به Mat تبدیل می کنیم و با Sobel ازش مشتق مرتبه اول می گیریم تا تغییرات را شعاع های مجاور ببینیم سپس چون مقادیر مشتق با توجه به ضربه هایی که میزنه منفی و مثبت میشه ما قدر مطلق این مقادیر را بدست میاریم و ضربه های کوچک را به عنوان نویز در نظر می گیریم و حذف می کنیم.سپس مجموع میزان این تغییرات را در هریک از آبجکت ها محاسبه می کنیم.
مرحله سوم در اینجا باید مقادیر را کلاسه بندی یا کلاسیفکیشن کنیم چون در این نمونه هایی که شما قرار دادید تعدادشون کمه من خودم دستی اینکار را انجام دادم ولی برای تعداد نمونه های بالا بهتره از یک کلاسفیر مثل SVM برای اینکار استفاده کنیم.
#include "stdafx.h"
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Point massOfcenter(const vector<Point>& contour){
Moments mu = moments(contour, false);
return Point(mu.m10 / mu.m00, mu.m01 / mu.m00);
}
vector<float> getRadiuses(const vector<Point>& contour, const Point& center){
vector<float> result;
result.reserve(contour.size());
for (auto& pnt : contour)
result.push_back((int)norm(pnt - center));
return result;
}
float circularity(const vector<Point>& contour, const Point& center){
vector<float> radiuses = getRadiuses(contour, center);
Scalar me_val, std_dev_val;
meanStdDev(Mat(radiuses), me_val, std_dev_val);
return std_dev_val.val[0];
}
int main()
{
const float scale = 5.f;
Mat color_img = imread("d:/Untitled-3.png", 1);
resize(color_img, color_img, cv::Size(color_img.cols * scale, color_img.rows * scale), 0, 0, CV_INTER_CUBIC);
Mat gray_img;
cvtColor(color_img, gray_img, CV_BGR2GRAY);
bitwise_not(gray_img, gray_img);
medianBlur(gray_img, gray_img, 3);
threshold(gray_img, gray_img, 100, 255, CV_THRESH_OTSU);
GaussianBlur(gray_img, gray_img,Size(5,5),0);
threshold(gray_img, gray_img, 100, 255, CV_THRESH_OTSU);
vector<vector<Point>> contours;
findContours(gray_img, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
vector<Moments> mu(contours.size());
vector<Point> mc(contours.size());
string state ;
for (int i = 0; i < contours.size(); i++){
Point center = massOfcenter(contours[i]);
vector<float> radiuses = getRadiuses(contours[i], center);
Mat rad(radiuses);
Mat sobel_rad;
Sobel(rad, sobel_rad, CV_32FC1, 0, 1);
sobel_rad = abs(sobel_rad);
threshold(sobel_rad, sobel_rad, 8, 255, CV_THRESH_TOZERO);
float circularity_cofi = sum(sobel_rad).val[0];
if (circularity_cofi < 25)
state = "salem";
else if (circularity_cofi < 120)
state = "khordegi";
else if (circularity_cofi)
state = "paregi";
stringstream ss;
ss << state;
putText(color_img, ss.str(), center,3, 2, CV_RGB(255, 0, 0), 3);
}
imwrite("d:/res.png", color_img);
imshow("view", color_img);
waitKey(0);
return 0;
}