3

我正在尝试使用mexopencv将特征匹配和单应性重新编码。Mexopencv将 OpenCV 视觉工具箱移植到 Matlab 中。

我在 Matlab 中使用 OpenCV 工具箱的代码:

function hello

    close all;clear all;

    disp('Feature matching demo, press key when done');

    boxImage = imread('D:/pic/500_1.jpg');

    boxImage = rgb2gray(boxImage);

    [boxPoints,boxFeatures] = cv.ORB(boxImage);

    sceneImage = imread('D:/pic/100_1.jpg');

    sceneImage = rgb2gray(sceneImage);

    [scenePoints,sceneFeatures] = cv.ORB(sceneImage);

    if (isempty(scenePoints)|| isempty(boxPoints)) 
        return;
    end;


    matcher = cv.DescriptorMatcher('BruteForce');
    matches = matcher.match(boxFeatures,sceneFeatures);


    %Box contains pixels coordinates where there are matches
    box = [boxPoints([matches(2:end).queryIdx]).pt];

    %Scene contains pixels coordinates where there are matches
    scene = [scenePoints([matches(2:end).trainIdx]).pt];

    %Please refer to http://stackoverflow.com/questions/4682927/matlab-using-mat2cell

    %Box arrays contains coordinates the form [ (x1,y1), (x2,y2) ...]
    %after applying mat2cell function
    [nRows, nCols] = size(box);
    nSubCols = 2;
    box = mat2cell(box,nRows,nSubCols.*ones(1,nCols/nSubCols));

    %Scene arrays contains coordinates the form [ (x1,y1), (x2,y2) ...]
    %after applying mat2cell function

    [nRows, nCols] = size(scene);
    nSubCols = 2;
    scene = mat2cell(scene,nRows,nSubCols.*ones(1,nCols/nSubCols));

    %Finding homography between box and scene
    H = cv.findHomography(box,scene);

    boxCorners = [1, 1;...                           % top-left
        size(boxImage, 2), 1;...                 % top-right
        size(boxImage, 2), size(boxImage, 1);... % bottom-right
        1, size(boxImage, 1)];

  %Fine until this point , problem starts with perspectiveTransform   
  sceneCorners= cv.perspectiveTransform(boxCorners,H); 

end

错误:

    Error using cv.perspectiveTransform
Unexpected Standard exception from MEX file.
What()
is:C:\slave\builds\WinInstallerMegaPack\src\opencv\modules\core\src\matmul.cpp:1926:
error: (-215) scn + 1 == m.cols && (depth == CV_32F || depth == CV_64F)

..

Error in hello (line 58)
  sceneCorners= cv.perspectiveTransform(boxCorners,H);

问题从检查开始perspectiveTranform(boxCorners, H),直到发现homography它很好。另请注意,在从样本和场景计算匹配坐标时,我从2:end, 开始索引box = [boxPoints([matches(2:end).queryIdx]).pt],因为访问queryIdx第一个元素的 将产生无法访问的第零个位置。不过,我认为,这不会是一个问题。无论如何,我期待我的解决方案的答案。谢谢。

PS:这是我在这里的原始帖子的编辑版本。我在下面收到的解决方案不够充分,并且该错误不断重复。

第二次更新:

根据@Amro,我已经更新了我的代码,如下。内点给出了很好的响应,但是计算透视变换的坐标不知何故被扭曲了。

function hello
    close all; clear all; clc;

    disp('Feature matching with ORB');

    %Feature detector and extractor for object
    imgObj = imread('D:/pic/box.png');
    %boxImage = rgb2gray(boxImage);
    [keyObj,featObj] = cv.ORB(imgObj);

    %Feature detector and extractor for scene
    imgScene = imread('D:/pic/box_in_scene.png');
    %sceneImage = rgb2gray(sceneImage);
    [keyScene,featScene] = cv.ORB(imgScene);

    if (isempty(keyScene)|| isempty(keyObj)) 
        return;
    end;

    matcher = cv.DescriptorMatcher('BruteForce-HammingLUT');
    m = matcher.match(featObj,featScene);

    %im_matches = cv.drawMatches(boxImage, boxPoints, sceneImage, scenePoints,m);

    % extract keypoints from the filtered matches
    % (C zero-based vs. MATLAB one-based indexing)
    ptsObj = cat(1, keyObj([m.queryIdx]+1).pt);
    ptsObj = num2cell(ptsObj, 2);
    ptsScene = cat(1, keyScene([m.trainIdx]+1).pt);
    ptsScene = num2cell(ptsScene, 2);

    % compute homography
    [H,inliers] = cv.findHomography(ptsObj, ptsScene, 'Method','Ransac');

    % remove outliers reported by RANSAC
    inliers = logical(inliers);
    m = m(inliers);

    % show the final matches
    imgMatches = cv.drawMatches(imgObj, keyObj, imgScene, keyScene, m, ...
    'NotDrawSinglePoints',true);
    imshow(imgMatches);

    % apply the homography to the corner points of the box
    [h,w] = size(imgObj);
    corners = permute([0 0; w 0; w h; 0 h], [3 1 2]);
    p = cv.perspectiveTransform(corners, H)
    p = permute(p, [2 3 1])
    p = bsxfun(@plus, p, [size(imgObj,2) 0]);

    % draw lines between the transformed corners (the mapped object)
    opts = {'Color',[0 255 0], 'Thickness',4};
    imgMatches = cv.line(imgMatches, p(1,:), p(2,:), opts{:});
    imgMatches = cv.line(imgMatches, p(2,:), p(3,:), opts{:});
    imgMatches = cv.line(imgMatches, p(3,:), p(4,:), opts{:});
    imgMatches = cv.line(imgMatches, p(4,:), p(1,:), opts{:});
    imshow(imgMatches)
    title('Matches & Object detection')

end

输出很好,但是perspectiveTranform没有给出适合问题的正确坐标。到目前为止我的输出:

输出

第三次更新:

我已经让所有的代码都在运行并且对单应性很好。然而,一个角落里的情况让我很难受。如果我这样做imgObj = imread('D:/pic/box.png')imgScene = imread('D:/pic/box_in_scene.png')我会得到很好的单应矩形,但是,当我这样做时imgScene = imread('D:/pic/box.png'),即对象和场景是相同的,我会得到这个错误 -

Error using cv.findHomography
Unexpected Standard exception from MEX file.
What()
is:C:\slave\builds\WinInstallerMegaPack\src\opencv\modules\calib3d\src\fundam.cpp:1074:
error: (-215) npoints >= 0 && points2.checkVector(2) == npoints && points1.type() ==
points2.type()

..

Error in hello (line 37)
    [H,inliers] = cv.findHomography(ptsObj, ptsScene, 'Method','Ransac');

现在,我过去遇到过这个错误,当ptsObjor的数量ptsScene很低时会发生这种情况,例如,当场景只是白/黑屏幕时,该场景的关键点为零。在这个特殊的问题中,有大量的ptsObjptsScene。问题出在哪里。我已经使用SURF相同的错误 resurfacing 测试了这段代码。

4

3 回答 3

4

几点说明:

  • 匹配器返回从零开始的索引(以及由于 OpenCV 在 C++ 中实现的各种其他函数)。因此,如果您想获得相应的关键点,您必须调整一(MATLAB 数组是基于一的)。mexopencv 故意不会为此自动调整。

  • cv.findHomographyMEX 函数接受点作为大小的数值数组(1xNx2例如:cat(3, [x1,x2,...], [y1,y2,...]))或作为N每个二元素向量的 - 大小的单元数组(即{[x1,y1], [x2,y2], ...})。在这种情况下,我不确定您的代码是否正确打包了这些点,无论哪种方式都可以变得更简单..

这是从 C++ 翻译成 MATLAB的完整演示:

% input images
imgObj = imread('box.png');
imgScene = imread('box_in_scene.png');

% detect keypoints and calculate descriptors using SURF
detector = cv.FeatureDetector('SURF');
keyObj = detector.detect(imgObj);
keyScene = detector.detect(imgScene);

extractor = cv.DescriptorExtractor('SURF');
featObj = extractor.compute(imgObj, keyObj);
featScene = extractor.compute(imgScene, keyScene);

% match descriptors using FLANN
matcher = cv.DescriptorMatcher('FlannBased');
m = matcher.match(featObj, featScene);

% keep only "good" matches (whose distance is less than k*min_dist )
dist = [m.distance];
m = m(dist < 3*min(dist));

% extract keypoints from the filtered matches
% (C zero-based vs. MATLAB one-based indexing)
ptsObj = cat(1, keyObj([m.queryIdx]+1).pt);
ptsObj = num2cell(ptsObj, 2);
ptsScene = cat(1, keyScene([m.trainIdx]+1).pt);
ptsScene = num2cell(ptsScene, 2);

% compute homography
[H,inliers] = cv.findHomography(ptsObj, ptsScene, 'Method','Ransac');

% remove outliers reported by RANSAC
inliers = logical(inliers);
m = m(inliers);

% show the final matches
imgMatches = cv.drawMatches(imgObj, keyObj, imgScene, keyScene, m, ...
    'NotDrawSinglePoints',true);
imshow(imgMatches)

% apply the homography to the corner points of the box
[h,w] = size(imgObj);
corners = permute([0 0; w 0; w h; 0 h], [3 1 2]);
p = cv.perspectiveTransform(corners, H);
p = permute(p, [2 3 1]);
p = bsxfun(@plus, p, [size(imgObj,2) 0]);

% draw lines between the transformed corners (the mapped object)
opts = {'Color',[0 255 0], 'Thickness',4};
imgMatches = cv.line(imgMatches, p(1,:), p(2,:), opts{:});
imgMatches = cv.line(imgMatches, p(2,:), p(3,:), opts{:});
imgMatches = cv.line(imgMatches, p(3,:), p(4,:), opts{:});
imgMatches = cv.line(imgMatches, p(4,:), p(1,:), opts{:});
imshow(imgMatches)
title('Matches & Object detection')

match_homography

现在,您可以尝试其他一种用于特征检测/提取的算法(在您的情况下为 ORB)。请记住,您可能需要调整上面的一些参数以获得良好的结果(例如,用于控制要保留多少关键点匹配的乘数)。


编辑:

就像我说的,在计算机视觉中没有一种适合所有解决方案的尺寸。您需要通过调整各种算法参数来进行实验,以便在数据上获得良好的结果。例如,ORB 构造函数接受一堆选项。此外,正如文档所建议的那样,具有汉明距离的蛮力匹配器是 ORB 描述符的推荐匹配器。

最后请注意,我指定了RANSAC鲁棒算法作为用于计算单应矩阵的方法;查看您发布的屏幕截图,您可以看到异常匹配错误地指向场景中的黑色计算机视觉书。RANSAC 方法的优点是即使在数据中存在大量异常值时也能准确地进行估计。使用的默认方法findHomography是使用所有可用的点。

此外请注意,在您的情况下,用于估计单应性的一些控制点几乎是共线的,这可能对计算有很大的影响(有点像如何在数值上反转接近奇异的矩阵是一个坏主意)。

如上所述,我在代码的相关部分下面突出显示,这些部分使用 ORB 描述符给了我很好的结果(其余部分与我之前发布的内容没有变化):

% detect keypoints and calculate descriptors using ORB
[keyObj,featObj] = cv.ORB(imgObj);
[keyScene,featScene] = cv.ORB(imgScene);

% match descriptors using brute force with Hamming distances
matcher = cv.DescriptorMatcher('BruteForce-Hamming');
m = matcher.match(featObj, featScene);

% keep only "good" matches (whose distance is less than k*min_dist )
dist = [m.distance];
m = m(dist < 3*min(dist));

ORB_matching

我注意到您省略了最后一部分,我通过删除坏匹配项来过滤匹配项。您始终可以查看找到的匹配项的“距离”的分布,并确定一个适当的阈值。这是我最初的:

hist([m.distance])
title('Distribution of match distances')

匹配距离分布

您还可以根据其响应值对原始关键点应用类似的过程,并相应地对这些点进行子采样:

subplot(121), hist([keyObj.response]); title('box')
subplot(122), hist([keyScene.response]); title('scene')

高温高压

于 2013-12-09T21:33:22.203 回答
2

图像处理工具箱和计算机视觉系统工具箱中的函数使用与您在大多数教科书中看到的不同的约定来转换点。在大多数教科书中,点都用列向量表示。所以你的变换看起来像这样:H * x,其中 H 是变换矩阵,x 是一个矩阵,其列是点。

另一方面,在 MATLAB 中,点通常表示为行向量。所以你必须切换乘法的顺序并转置H:x'* H'。

最后,如果您有适用于 MATLAB 的计算机视觉系统 Toolobx,您可以用更少的代码解决您的问题。看看这个例子

于 2013-12-02T15:15:11.583 回答
1

尝试使用 H.

我们将单应矩阵计算为:x'=H*x,但在 MATLAB 中,它看起来像这样的类型:x'^{T}=x^{T}*H^{T}(x'^{T} 表示x' 的转置)。所以,转置你的单应性然后再试一次。

于 2013-12-02T03:45:50.730 回答