OpenCV C++/Obj-C: правильное обнаружение объектов
Как какой-то "праздничный проект" я играю с OpenCV и хочу обнаружить и измерить материал.
Текущий рабочий процесс (ранняя стадия - обнаружение):
- Преобразовать в оттенки серого (cv::cvtColor)
- Применить адаптивный порог (cv::adaptiveThreshold)
- Применить обнаружение краев Canny (cv:: Canny)
- Поиск контуров (cv:: findContours)
Мой результат довольно дерьмовый, и я не уверен, в каком направлении идти. У меня уже есть cvBlob, работающий под моей текущей установкой (OSX 10.7.2, Xcode 4.2.1), это лучший способ? Если так, как я могу реализовать это правильно?
Или мне нужно сначала вычитание фона? Я попробовал это, но потом не смог найти контуры
Вот мое изображение:
И это мой вывод, когда я рисую свои контуры обратно в первое изображение:
ОБНОВИТЬ
Я получил это работает в моей программе, и мой вывод выглядит немного по-другому...
- (IBAction)processImage:(id)sender
{
cv::Mat forground = [[_inputView image] CVMat];
cv::Mat result = [self isolateBackground:forground];
[_outputView setImage:[NSImage imageWithCVMat:result]];
}
- (cv::Mat)isolateBackground:(cv::Mat &)_image
{
int rh = 255, rl = 100, gh = 255, gl = 0, bh = 70, bl = 0;
cv::cvtColor(_image, _image, CV_RGB2HSV_FULL);
cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
cv::Mat bgIsolation;
cv::inRange(_image, cv::Scalar(bl, gl, rl), cv::Scalar(bh, gh, rh), bgIsolation);
bitwise_not(bgIsolation, bgIsolation);
erode(bgIsolation, bgIsolation, cv::Mat());
dilate(bgIsolation, bgIsolation, element);
return bgIsolation;
}
1 ответ
Это может быть своего рода хаком, но так как это "праздничный проект", я все равно выложу его:)
Вы пытались изолировать фон и затем инвертировать маску (это предполагает, что все, что не фон, является объектом, но это может работать для того, что вы хотите).
Ниже приведен результат, полученный с помощью функции inRange OpenCV:
Возможно, вы захотите сгладить изображение (предварительную обработку) с помощью GuassianBlur, чтобы избавиться от некоторых неровностей. Я использовал ядро расширения большего размера, чем ядро эрозии (5x5 против 3x3), чтобы избавиться от некоторых шумных пикселей. Сглаживание может помочь в этом, также настройка порогов может сделать ненужной эрозию. Но это должно помочь вам начать.
Наконец, вот мой небольшой фрагмент кода, который я использовал, чтобы найти этот диапазон:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat src = imread("test.jpg");
int rh = 255, rl = 100, gh = 255, gl = 0, bh = 70, bl = 0;
string windowName = "background";
namedWindow(windowName);
createTrackbar("rh", windowName, &rh, 255);
createTrackbar("rl", windowName, &rl, 255);
createTrackbar("gh", windowName, &gh, 255);
createTrackbar("gl", windowName, &gl, 255);
createTrackbar("bh", windowName, &bh, 255);
createTrackbar("bl", windowName, &bl, 255);
// for dilation
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
Mat bgIsolation;
int key = 0;
do
{
inRange(src, Scalar(bl, gl, rl), Scalar(bh, gh, rh), bgIsolation);
bitwise_not(bgIsolation, bgIsolation);
erode(bgIsolation, bgIsolation, Mat());
dilate(bgIsolation, bgIsolation, element);
imshow(windowName, bgIsolation);
key = waitKey(33);
} while((char)key != 27);
waitKey();
return 0;
}
Наслаждайтесь праздничным проектом! Смотрится весело:)