簡體   English   中英

如何使用OpenCV檢測圖像梯度或正常

[英]How to detect image gradient or normal using OpenCV

我想檢測圖像中的橢圓。 當時我正在學習Mathematica,我在這里問了一個問題並從下面的答案得到了一個令人滿意的結果,它使用RANSAC算法來檢測橢圓。

但是,最近我需要將它移植到OpenCV,但有一些功能只存在於Mathematica中。 其中一個關鍵功能是“GradientOrientationFilter”功能。

由於一般橢圓有五個參數,我需要采樣五個點來確定一個。 但是,采樣點越多表示猜測的機會越小,這導致橢圓檢測的成功率越低。 因此,Mathematica的答案增加了另一個條件,即圖像的梯度必須與橢圓方程的梯度平行。 無論如何,我們只需要三個點來使用Mathematica方法中的最小二乘法確定一個橢圓。 結果非常好。

但是,當我嘗試在OpenCV中使用Sobel或Scharr運算符找到圖像漸變時,它不夠好,這總是會導致不良結果。

如何准確計算圖像的梯度或切線? 謝謝!


結果有漸變,三點 結果有漸變,三點

結果沒有漸變,五分 結果沒有漸變,五分

- - - - - 更新 - - - - -

我事先做了一些邊緣檢測和中值模糊,並在邊緣圖像上繪制結果。 我的原始測試圖像是這樣的:

原始測試圖像

通常,我的最終目標是檢測場景或對象中的橢圓。 像這樣的東西:

咖啡杯

這就是我選擇使用RANSAC從邊緣點擬合橢圓的原因。

至於你的最終目標,你可以試試

OpenCV中的findContours[fitEllipse]

偽代碼將是

1)一些圖像處理

2)找到所有輪廓

3)通過fitEllipse擬合每個輪廓

這是我之前使用的代碼的一部分

[... image process ....you get a bwimage ]

vector<vector<Point> > contours;
findContours(bwimage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);


for(size_t i = 0; i < contours.size(); i++)
{
    size_t count = contours[i].size();

    Mat pointsf;
    Mat(contours[i]).convertTo(pointsf, CV_32F);
    RotatedRect box = fitEllipse(pointsf);

    /* You can put some limitation about size and aspect ratio here */
    if( box.size.width > 20 && 
        box.size.height > 20 && 
        box.size.width < 80 && 
        box.size.height < 80 )
    {
    if( MAX(box.size.width, box.size.height) > MIN(box.size.width, box.size.height)*30 )
        continue;
    //drawContours(SrcImage, contours, (int)i, Scalar::all(255), 1, 8);

    ellipse(SrcImage, box, Scalar(0,0,255), 1, CV_AA);
    ellipse(SrcImage, box.center, box.size*0.5f, box.angle, 0, 360, Scalar(200,255,255), 1, CV_AA);
    }
}

imshow("result", SrcImage);

如果您專注於橢圓(沒有其他形狀),則可以將橢圓像素的值視為點的質量。

然后你可以計算慣性矩Ixx,Iyy,Ixy找出角度θ,它可以將一般橢圓旋轉回規范形式(X-Xc)^ 2 / a +(Y-Yc)^ 2 / b = 1。

然后你可以通過質心找到Xc和Yc。

然后你可以通過最小X和最小Y找出a和b。

---------------更新-----------

該方法也可以應用於填充橢圓。

除非先對它們進行分割,否則單個圖像上的多個橢圓將會失敗。

讓我解釋一下,我將使用C來表示cos(theta)和S來表示sin(theta)

在旋轉到規范形式之后,新X是[eq0] X = xC-yS並且Y是Y = xS + yC,其中x和y是原始位置。

輪換將給你最小的IYY。

[EQ1]

IYY = Sum(m * Y * Y)= Sum {m *(xS + yC) (xS + yC)} = Sum {m (xxSS + yyCC + xySC)= Ixx * S ^ 2 + Iyy * C ^ 2 + IXY * S * C

對於最小IYY,d(IYY)/ d(θ)= 0即為

2IxxSC - 2IyySC + Ixy(CC-SS)= 0

2(Ixx-Iyy)/ Ixy =(SS-CC)/ SC = S / C + C / S = Z + 1 / Z

在編程時,LHS只是一個數字,讓我們說N.

Z ^ 2 - NZ +1 = 0

所以有兩個Z因此theta的根,讓我們說Z1和Z2,一個將使IYY縮小,另一個將最大化IYY。

-----------偽代碼--------

計算Ixx,Iyy,Ixy為空心或填充橢圓。

計算theta1 = atan(Z1)和theta2 = atan(Z2)

將這兩個theta放入eq1中查找哪個更小。 然后你得到theta。

回到那些非零像素,通過你找到的theta將它們傳輸到新的X和Y.

通過sort()找到質心Xc Yc和min X和min Y.

- - - - - - - 用手 - - - - - -

如果需要橢圓的原始方程

只需將[eq0]放入規范形式即可

你以不尋常的方式使用術語。

通常對於圖像 ,術語“梯度”被解釋為好像圖像是數學函數f(x,y) 這給了我們每個點的(df/dx, df/dy)向量。

然而,您正在將圖像看作是函數y = f(x) ,並且梯度將是f(x)/dx

現在,如果你看一下你的形象,你會發現兩種解釋肯定是相關的。 您的橢圓被繪制為一組對比像素,因此圖像中有兩個銳利的漸變 - 內部和外部。 這些當然對應於兩個法向量,因此是相反的方向。

另請注意,您的圖片包含像素。 漸變也是像素化的。 使用單個像素寬度繪制橢圓的方式意味着局部漸變僅采用45度的倍數值:

▄▄ ▄▀ ▌ ▀▄

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM