Распознавание объектов в изображениях с помощью каскада HAAR и OpenCV
(Это вышло немного долго, но это в основном трудно понять объяснение :)
для проекта мне нужно распознать объекты, которые в общем виде выглядят так -
внутри большего изображения, которое содержит различные формы, как этот -
как вы можете видеть, объект, который я ищу, - это красная линия с крестами с каждой стороны (на последнем снимке их 5). У меня есть банк вокруг 4000 изображений, в которых мне нужно найти объект, некоторые из них содержат эти объекты, а некоторые нет, как это изображение -
после проведения некоторых исследований я понял, что использование каскадов haar и openCV-это путь, поэтому я написал сценарий, который проходит через все вышеупомянутые изображения 4,000 и извлекает отдельные контуры, как первое изображение в этом вопросе.
затем я прошел через множество контуров, схватил около 150 из них (то есть 150 файлов которые содержат только нужный мне объект, похожий на первое изображение) и около 180 изображений, которые не содержат нужного мне объекта (аналогично третьему изображению здесь).
затем я начал учебный процесс, используя несколько учебных пособий, но в основном этот.
при этом я столкнулся с проблемой - как вы можете видеть, изображения желаемого объекта с двойным пересечением не имеют одинакового размера и даже не имеют одинакового масштаба (поскольку они могут отображаться под любым углом - горизонтально, по диагонали и т. д..).
сначала я попытался использовать изображения с другим измерением, но это вызвало ошибки в процессе обучения, поэтому, чтобы обойти это, я изменил размер всех положительных изображений на 350x350 (самый большой масштаб одного из объектов). Просто чтобы быть ясным - я не изменял размер изображений - я просто добавил пробел, чтобы все изображения были 350x350 пикселей.
затем я прошел через учебный процесс, как было предложено в учебнике-я создал образцы (ширина-24, высота-24) и создал каскадный xml-файл, который оказался не очень большим (45кб).
Теперь я знаю, что 150 положительных изображений и 180 отрицательных-это не так много, но я хотел, по крайней мере, получить доказательство концепции, прежде чем фильтровать больше изображений и вкладывать в него больше времени.
когда каскад.XML-файл был сделан, я попытался использовать его, чтобы найти некоторые объекты в некоторых изображений (используя cv2.CascadeClassifier('cascade.xml')
и cascade.detectMultiScale(img)
но каждая попытка результат нулевой.
наконец я даже попытался найти объект в одном из положительных изображений (который не содержал ничего, кроме одного из желаемых объектов), но он также вернул нулевые результаты.
Я попытался настроить параметры cascade.detectMultiScale(img)
и в настоящее время я тренирую каскадный файл с образцами 36x36, но я не уверен, что он будет работать.
Так как я довольно новичок в этом материале, мне было интересно, что я делаю неправильно, и я подумал, что спрошу здесь.
более конкретно:
- считаете ли вы, что использование haar правильно в этом контексте? Должен ли я использовать другой метод распознавания объектов?
- могут ли положительные размеры изображений быть источником проблемы? Если да, то как я могу это сделать?
Если я не включил некоторые важные данные, пожалуйста, дайте мне знать и я выложу его.
большое спасибо за вашу помощь, Дэн!--4-->
1 ответов
Я думаю, вы не получите хороших результатов от каскадных классификаторов haar (или hog) здесь.
- ваша "игла" не имеет достаточного количества функций / углов (это всего лишь 2 креста и линия)
- каскадные классификаторы довольно чувствительны к вращению. кажется, ваш объект может принимать любое произвольное вращение здесь.
- если вы тренируете классификатор со многими различными вращениями, он будет просто overfit.
- если вы тренируетесь много классификаторы(по одному на ротация), - то же самое. ;(
Итак, имхо, не много надежды на такой подход.
Я бы пошел для контуров/shapeMatching вместо этого:
void findNeedles( const std::vector<cv::Point> & needle_contour, const cv::Mat & haystack_binarized)
{
int nfound = 0;
std::vector<std::vector<cv::Point>> contours;
cv::findContours(haystack_binarized, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
for (size_t i = 0; i < contours.size(); i++)
{
// pre-filter for size:
if ( ( contours[i].size() < needle_contour.size()/2 )
|| ( contours[i].size() > needle_contour.size()*2 ) )
continue;
double d = cv::matchShapes(contours[i],needle_contour,CV_CONTOURS_MATCH_I2,0);
if ( d < 8.4 ) // heuristic value, experiments needed !!
{
cv::drawContours(haystack_binarized, contours, i, 128, 3);
nfound ++;
}
}
cerr << nfound << " objects found" << endl;
cv::imshow("haystack",haystack_binarized);
//imwrite("hay.png",haystack_binarized);
cv::waitKey();
}
int main()
{
// 1. get the contour of our needle:
Mat needle = imread("needle.png",0);
Mat needle_b;
threshold(needle,needle_b,120,255,1);
imshow("needle",needle_b);
std::vector<std::vector<cv::Point>> needle_conts;
cv::findContours(needle_b, needle_conts, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
if ( needle_conts.size() == 0 )
{
std::cout << " no contour Found" << std::endl;
return -1;
}
std::vector<cv::Point> needle_contour = needle_conts[0];
// 2. check a positive sample:
Mat haypos = imread("hay_pos.png",0);
Mat haypos_b;
threshold(haypos,haypos_b,120,255,1);
findNeedles(needle_contour, haypos_b);
// 3. check a negative sample:
Mat hayneg = imread("hay_neg.png",0);
Mat hayneg_b;
threshold(hayneg,hayneg_b,120,255,1);
findNeedles(needle_contour, hayneg_b);
return 0;
}
--------------
> haystack.exe
5 objects found
0 objects found