Opencv: конвертировать Scalar в float или double type
Может ли кто-нибудь помочь мне в преобразовании скалярного типа openCV в базовые типы, такие как float или double?
Scalar Sum1=sum(arg1),Sum2=sum(arg2);
theta.at<float>(i,j)=0.5*atan(Sum1/Sum2);
Мне нужно суммировать все элементы объектов Mat arg1
и arg2
(сумма окрестности), тогда я должен выполнить их деление, чтобы найти поле ориентации в каждом пикселе. Я выполнил сумму, но поскольку я должен применить функцию 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);
}
}
Ответы
Ответ 1
ИЗМЕНИТЬ
Из документов OpenCV:
сумма
...
Сумма функций вычисляет и возвращает сумму элементов массива, независимо для каждого канала.
Выходные изображения, которые генерирует Sobel, представляют собой двоичные изображения с одним каналом, так как ваши результаты Sum1
и Sum2
Scalars из-за того, что вам нужно использовать atan(Sum1[0]/Sum2[0])
для вычисления основного значения касательной дуги.
WRONG, поскольку фильтр Log-Gabor должен быть применен...
Похоже, вы пытаетесь сделать много вещей, которые можно было бы обработать с помощью cv::filter2D()
... Если вы хотите применить фильтр Gabor к своему изображению, взгляните на это, и я нашел здесь:
#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;
}
Ответ 2
Я использую
double s;
s = sum(arg1)[0];
Ответ 3
Скаляр - это 4-элементный вектор удвоений, полученных из Vec, как показано в документации opencv (http://docs.opencv.org/2.4.9/modules/core/doc/basic_structures.html#scalar)
Функция cv:: sum суммирует элементы из каждого канала отдельно, если матрица имеет более одного канала и сохраняет их на Scalar 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];