【问题标题】:opencv: convert Scalar to float or double typeopencv:将标量转换为浮点型或双精度型
【发布时间】:2012-06-19 18:05:04
【问题描述】:

谁能帮我将 openCV 的标量类型转换为浮点或双精度等基本类型?

Scalar Sum1=sum(arg1),Sum2=sum(arg2);
theta.at<float>(i,j)=0.5*atan(Sum1/Sum2);

我必须将 Mat 对象 arg1 和 arg2 的所有元素相加(邻域总和),然后我必须执行它们的除法以找到每个像素的方向场。我执行了 sum,但由于我必须应用 arctan 函数,所以标量类型不适合。谁能帮我将标量类型转换为基本类型?

实际上我正在尝试应用 log-gabor 过滤器,到目前为止我所做的代码是:

//function to enhance fingerprint by log-gabor filter

void filter(Mat src, Mat finalImage)
{

//Sobel derivatives for orientation estimation

Mat grad_x,grad_y,grad2_x,grad2_y,fImage;
src.convertTo(fImage, CV_32F);

//1st and second order gradient

Sobel(fImage,grad_x,CV_32F,1,0,3);
Sobel(fImage,grad_y,CV_32F,0,1,3);    
Sobel(fImage,grad2_x,CV_32F,2,0,3);
Sobel(fImage,grad2_y,CV_32F,0,2,3);

//orientation estimation

Mat theta=Mat::zeros(fImage.size(),CV_32F);
Size block=Size(12,12);
copyMakeBorder(grad_x, grad_x, block.height/2, block.height/2,
               block.width/2,block.width/2 , BORDER_CONSTANT, Scalar::all(0));

copyMakeBorder(grad2_x, grad2_x, block.height/2, block.height/2,
               block.width/2,block.width/2 , BORDER_CONSTANT, Scalar::all(0));

copyMakeBorder(grad_y, grad_y, block.height/2, block.height/2,
               block.width/2,block.width/2 , BORDER_CONSTANT, Scalar::all(0));

copyMakeBorder(grad2_y, grad2_y, block.height/2, block.height/2,
               block.width/2,block.width/2 , BORDER_CONSTANT, Scalar::all(0));
Size imgSz=grad_x.size();
for(int i=block.width/2;i<imgSz.width-block.width/2;++i)
    for(int j=block.height/2;j<imgSz.height-block.height/2;++j)
    {
        Mat roi_gradX=grad_x(Range(i-block.width/2,i+block.width/2),
                             Range(j-block.width/2,j+block.width/2));

        Mat roi_gradY=grad_y(Range(i-block.width/2,i+block.width/2),
                             Range(j-block.width/2,j+block.width/2));

        Mat roi_gradX2=grad2_x(Range(i-block.width/2,i+block.width/2),
                             Range(j-block.width/2,j+block.width/2));

        Mat roi_gradY2=grad2_y(Range(i-block.width/2,i+block.width/2),
                             Range(j-block.width/2,j+block.width/2));

        Mat arg1,arg2;
        multiply(roi_gradX,roi_gradY,arg1);
        arg1*=2;
        subtract(roi_gradX2,roi_gradY2,arg2);
        Scalar Sum1=sum(arg1),Sum2=sum(arg2);

        theta.at<float>(i,j)=0.5*atan(Sum1/Sum2);
    }
}

【问题讨论】:

  • 我正在尝试应用 log-gabor 过滤器来增强指纹.....我已经编辑了我的帖子并添加了代码.....

标签: c opencv scalar


【解决方案1】:

编辑

来自 OpenCV 文档:

总和
...
函数 sum 计算并返回数组元素的总和, 每个频道独立。

Sobel 生成的输出图像是具有一个通道的二进制图像,因为您的 Sum1 和 Sum2 标量结果是您需要使用 atan(Sum1[0]/Sum2[0]) 来计算反正切的主值。

错误应该应用 Log-Gabor 过滤器……

看起来你尝试做很多事情,这可以由cv::filter2D() 处理……如果你想对你的图像应用 Gabor 过滤器,那么看看这个,我找到了here:

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <math.h>

cv::Mat mkKernel(int ks, double sig, double th, double lm, double ps)
{
    int hks = (ks-1)/2;
    double theta = th*CV_PI/180;
    double psi = ps*CV_PI/180;
    double del = 2.0/(ks-1);
    double lmbd = lm;
    double sigma = sig/ks;
    double x_theta;
    double y_theta;
    cv::Mat kernel(ks,ks, CV_32F);
    for (int y=-hks; y<=hks; y++)
    {
        for (int x=-hks; x<=hks; x++)
        {
            x_theta = x*del*cos(theta)+y*del*sin(theta);
            y_theta = -x*del*sin(theta)+y*del*cos(theta);
            kernel.at<float>(hks+y,hks+x) = (float)exp(-0.5*(pow(x_theta,2)+pow(y_theta,2))/pow(sigma,2))* cos(2*CV_PI*x_theta/lmbd + psi);
        }
    }
    return kernel;
}

int kernel_size=21;
int pos_sigma= 5;
int pos_lm = 50;
int pos_th = 0;
int pos_psi = 90;
cv::Mat src_f;
cv::Mat dest;

void Process(int , void *)
{
    double sig = pos_sigma;
    double lm = 0.5+pos_lm/100.0;
    double th = pos_th;
    double ps = pos_psi;
    cv::Mat kernel = mkKernel(kernel_size, sig, th, lm, ps);
    cv::filter2D(src_f, dest, CV_32F, kernel);
    cv::imshow("Process window", dest);
    cv::Mat Lkernel(kernel_size*20, kernel_size*20, CV_32F);
    cv::resize(kernel, Lkernel, Lkernel.size());
    Lkernel /= 2.;
    Lkernel += 0.5;
    cv::imshow("Kernel", Lkernel);
    cv::Mat mag;
    cv::pow(dest, 2.0, mag);
    cv::imshow("Mag", mag);
}

int main(int argc, char** argv)
{
    cv::Mat image = cv::imread("cat.jpg",1);
    cv::imshow("Src", image);
    cv::Mat src;
    cv::cvtColor(image, src, CV_BGR2GRAY);
    src.convertTo(src_f, CV_32F, 1.0/255, 0);
    if (!kernel_size%2)
    {
        kernel_size+=1;
    }
    cv::namedWindow("Process window", 1);
    cv::createTrackbar("Sigma", "Process window", &pos_sigma, kernel_size, Process);
    cv::createTrackbar("Lambda", "Process window", &pos_lm, 100, Process);
    cv::createTrackbar("Theta", "Process window", &pos_th, 180, Process);
    cv::createTrackbar("Psi", "Process window", &pos_psi, 360, Process);
    Process(0,0);
    cv::waitKey(0);
    return 0;
}

【讨论】:

  • 感谢您的回答,但这是用于 gabor 过滤器,我正在研究 log-gabor 过滤器.....比这更先进,但它会提供很多想法...... .但我仍然必须将标量类型转换为基本类型,如浮点数.....你能建议我的方法吗???
【解决方案2】:

我用

double s;
s = sum(arg1)[0];

【讨论】:

    【解决方案3】:

    Scalar 是从 Vec 派生的双精度的 4 元素向量,如 opencv 文档 (http://docs.opencv.org/2.4.9/modules/core/doc/basic_structures.html#scalar) 中所示

    如果矩阵有多个通道,函数 cv::sum 分别对每个通道的元素求和,并将它们存储在标量 Vec 上。因此,要访问每个通道的双精度值,您必须访问向量上的位置。 (文档:http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#sum)

    //sum for first channel
    double sum1 = cv::sum(my_mat)[0];
    //sum for second channel
    double sum2 = cv::sum(my_mat)[1];
    //sum for third channel
    double sum3 = cv::sum(my_mat)[2];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-12
      • 2018-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多