opencv-通过添加R+将3个通道合并为1个通道;G+;B

opencv-通过添加R+将3个通道合并为1个通道;G+;B,opencv,Opencv,在OpenCV中,是否有一种简单的方法将BGR图像转换为单通道图像,其中每个像素是B、G和R的总和 例如,以下矩阵: [ [1, 2, 3], [4, 5, 6], [10, 20, 30], [40, 50, 60] ] 转换为: [ [6], [15], [60], [150] ] 我知道我可以在3个频道的图像上使用split,然后添加所有三个频道,但我想知道是否有更直接的内容。 thx [编辑] 我要做的是计算图像的结构张量,如中所述。结构张量定义为: 其中Lx、ax和

在OpenCV中,是否有一种简单的方法将BGR图像转换为单通道图像,其中每个像素是B、G和R的总和

例如,以下矩阵:

[
  [1, 2, 3], [4, 5, 6],
  [10, 20, 30], [40, 50, 60]
]
转换为:

[
  [6], [15],
  [60], [150]
]
我知道我可以在3个频道的图像上使用
split
,然后添加所有三个频道,但我想知道是否有更直接的内容。 thx

[编辑]

我要做的是计算图像的结构张量,如中所述。结构张量定义为:
其中Lx、ax和bx是L、a、b通道的索贝尔导数

我当前的实施(如果我正确理解了本文):

//加载并转换为Lab(使用32F矩阵保留原始Lab值)
Mat实验室;
图像转换器(实验室,CV_32F,1/255.0);
CVT颜色(实验室、实验室、颜色实验室);
//计算两个方向的导数
matdx,dy;
Sobel(实验室,dx,CV_32F,1,0,3);
Sobel(实验室,dy,CV_32F,0,1,3);
//现在需要通过添加L^2+a^2+b^2将dx转换为单通道
matdx2;
乘法(dx,dx,dx2);
载体dx2Cnls;
分割(dx2,dx2Cnls);
材料E=dx2Cnls[0]/*Lx^2*/+dx2Cnls[1]/*ax^2*/+dx2Cnls[2]/*bx^2*/;
//对dy也一样
Mat-dy2;
乘法(dy,dy,dy2);
载体dy2Cnls;
分裂(dy2,dy2Cnls);
Mat G=dy2Cnls[0]/*Ly^2*/+dy2Cnls[1]/*ay^2*/+dy2Cnls[2]/*by^2*/;
//现在是交叉点dx*dy
Mat-dxdy;
乘法(dx,dy,dxdy);
矢量dxdyCnls;
拆分(dxdy、dxdyCnls);
Mat F=dxdyCnls[0]/*LxLy*/+dxdyCnls[1]/*axay*/+dxdyCnls[2]/*bxby*/;

< >避免任何代码<拆分< /代码>,以便组合3个通道(

C++),可以使用FueCH成员:

cv::Mat img1(200, 200, CV_8UC3, cv::Scalar(10, 50, 150));
cv::Mat img2(img1.size(), CV_32FC1, cv::Scalar(0, 0, 0));
img2.forEach<float>([&](float& pix, const int position[])
{
    cv::Vec3b p = img1.at<cv::Vec3b>(position[1], position[0]);
    pix = p[0] + p[1] + p[2];
});
cv::Mat img1(200200,cv_8UC3,cv::Scalar(10,50150));
cv::Mat img2(img1.size(),cv_32FC1,cv::Scalar(0,0,0));
img2.forEach([&](float&pix,const int position[])
{
cv::Vec3b p=img1.at(位置[1],位置[0]);
pix=p[0]+p[1]+p[2];
});

对于C++,你可以使用FrACH成员:

cv::Mat img1(200, 200, CV_8UC3, cv::Scalar(10, 50, 150));
cv::Mat img2(img1.size(), CV_32FC1, cv::Scalar(0, 0, 0));
img2.forEach<float>([&](float& pix, const int position[])
{
    cv::Vec3b p = img1.at<cv::Vec3b>(position[1], position[0]);
    pix = p[0] + p[1] + p[2];
});
cv::Mat img1(200200,cv_8UC3,cv::Scalar(10,50150));
cv::Mat img2(img1.size(),cv_32FC1,cv::Scalar(0,0,0));
img2.forEach([&](float&pix,const int position[])
{
cv::Vec3b p=img1.at(位置[1],位置[0]);
pix=p[0]+p[1]+p[2];
});

一旦计算出导数,进一步的处理将独立处理每个像素位置。这意味着我们可以利用内存中像素数据的布局,并将其转换为更方便的形状

我们可以将
dx
dy
转换为1通道
Mat
s,具有3列(以及宽*高行)——每个原始像素位于一个新行上,第一列对应于
L
通道,第二列对应于
a
,第三列对应于
b
。整形是一个O(1)操作,因此成本可以忽略不计

每个元素的乘法仍将以相同的方式工作(尽管我们可以使用a而不是使事情更加简洁)

然后,我们可以使用获得每行(即每像素)和

最后,将
E
F
G
重塑为原始宽度/高度


示例代码

#include <opencv2/opencv.hpp>

int main()
{
    // Make some random data
    cv::Mat img(16, 16, CV_8UC3);
    cv::randu(img, 0, 256);

    // Load and convert to Lab (keeping the raw lab values by using 32F matrix)
    cv::Mat lab;
    img.convertTo(lab, CV_32F, 1 / 255.0);
    cv::cvtColor(lab, lab, cv::COLOR_BGR2Lab);

    // Compute derivatives in both directions 
    cv::Mat dx, dy;
    cv::Sobel(lab, dx, CV_32F, 1, 0, 3);
    cv::Sobel(lab, dy, CV_32F, 0, 1, 3);

    // Reshape the arrays to 1-channel, such that each original pixel is on
    // one row, first column is L, second is a, third is b
    // NB: This is O(1) operation.
    int new_row_count(lab.rows * lab.cols);
    dx = dx.reshape(1, new_row_count);
    dy = dy.reshape(1, new_row_count);

    // Get per-row (i.e. per pixel) sums for dx*dx, dx*dy, and dy*dy
    cv::Mat E, F, G;
    cv::reduce(dx.mul(dx), E, 1, cv::REDUCE_SUM);
    cv::reduce(dx.mul(dy), F, 1, cv::REDUCE_SUM);
    cv::reduce(dy.mul(dy), G, 1, cv::REDUCE_SUM);

    // Return back to original shape (but now only single channel)
    E = E.reshape(1, lab.rows);
    F = F.reshape(1, lab.rows);
    G = G.reshape(1, lab.rows);

    return 0;
}
我们可以看到,这基本上是一个:

因此,我们可以使用
cv::Vec3f::dot
优雅地计算结果

与使用
重塑
减少
的方法相比,最终实现所需的时间大约减少40%

示例代码

#include <opencv2/opencv.hpp>

int main()
{
    // Make some random data
    cv::Mat img(16, 16, CV_8UC3);
    cv::randu(img, 0, 256);

    // Load and convert to Lab (keeping the raw lab values by using 32F matrix)
    cv::Mat lab;
    img.convertTo(lab, CV_32F, 1 / 255.0);
    cv::cvtColor(lab, lab, cv::COLOR_BGR2Lab);

    // Compute derivatives in both directions 
    cv::Mat dx, dy;
    cv::Sobel(lab, dx, CV_32F, 1, 0, 3);
    cv::Sobel(lab, dy, CV_32F, 0, 1, 3);

    // Reshape the arrays to 1-channel, such that each original pixel is on
    // one row, first column is L, second is a, third is b
    // NB: This is O(1) operation.
    int new_row_count(lab.rows * lab.cols);
    dx = dx.reshape(1, new_row_count);
    dy = dy.reshape(1, new_row_count);

    // Get per-row (i.e. per pixel) sums for dx*dx, dx*dy, and dy*dy
    cv::Mat E, F, G;
    cv::reduce(dx.mul(dx), E, 1, cv::REDUCE_SUM);
    cv::reduce(dx.mul(dy), F, 1, cv::REDUCE_SUM);
    cv::reduce(dy.mul(dy), G, 1, cv::REDUCE_SUM);

    // Return back to original shape (but now only single channel)
    E = E.reshape(1, lab.rows);
    F = F.reshape(1, lab.rows);
    G = G.reshape(1, lab.rows);

    return 0;
}

#包括
孔隙结构张量(cv::Mat const&img,cv::Mat&E,cv::Mat&F,cv::Mat&G)
{
//加载并转换为Lab(使用32F矩阵保留原始Lab值)
cv::Mat实验室;
图像转换器(实验室,CV_32F,1/255.0);
cv::CVT颜色(实验室,实验室,cv::颜色实验室);
//计算两个方向的导数
cv::Mat dx,dy;
cv::Sobel(实验室,dx,cv_32F,1,0,3);
cv::Sobel(实验室,dy,cv_32F,0,1,3);
E.创建(实验室尺寸(),CV_32FC1);
F.创建(实验室尺寸(),CV_32FC1);
G.创建(实验室尺寸(),CV_32FC1);
for(int r(0);rdot(*idx);
*如果++=idx->dot(*idy);
*iG++=idy->dot(*idy);
}
/*或者像这样,选择你更喜欢的。
for(int c(0);c
一旦计算出导数,进一步的处理将独立处理每个像素位置。这意味着我们可以利用内存中像素数据的布局,并将其转换为更方便的形状

我们可以将
dx
dy
转换为1通道
Mat
s,具有3列(以及宽*高行)——每个原始像素位于一个新行上,第一列对应于
L
通道,第二列对应于
a
,第三列对应于
b
。整形是一个O(1)操作,因此成本可以忽略不计

每个元素的乘法仍将以相同的方式工作(尽管我们可以使用a而不是使事情更加简洁)

然后,我们可以使用获得每行(即每像素)和

最后,将
E
F
G
重塑为原始宽度/高度


示例代码

#include <opencv2/opencv.hpp>

int main()
{
    // Make some random data
    cv::Mat img(16, 16, CV_8UC3);
    cv::randu(img, 0, 256);

    // Load and convert to Lab (keeping the raw lab values by using 32F matrix)
    cv::Mat lab;
    img.convertTo(lab, CV_32F, 1 / 255.0);
    cv::cvtColor(lab, lab, cv::COLOR_BGR2Lab);

    // Compute derivatives in both directions 
    cv::Mat dx, dy;
    cv::Sobel(lab, dx, CV_32F, 1, 0, 3);
    cv::Sobel(lab, dy, CV_32F, 0, 1, 3);

    // Reshape the arrays to 1-channel, such that each original pixel is on
    // one row, first column is L, second is a, third is b
    // NB: This is O(1) operation.
    int new_row_count(lab.rows * lab.cols);
    dx = dx.reshape(1, new_row_count);
    dy = dy.reshape(1, new_row_count);

    // Get per-row (i.e. per pixel) sums for dx*dx, dx*dy, and dy*dy
    cv::Mat E, F, G;
    cv::reduce(dx.mul(dx), E, 1, cv::REDUCE_SUM);
    cv::reduce(dx.mul(dy), F, 1, cv::REDUCE_SUM);
    cv::reduce(dy.mul(dy), G, 1, cv::REDUCE_SUM);

    // Return back to original shape (but now only single channel)
    E = E.reshape(1, lab.rows);
    F = F.reshape(1, lab.rows);
    G = G.reshape(1, lab.rows);

    return 0;
}
我们可以看到,这基本上是一个:

因此,我们可以使用
cv::Vec3f::dot
优雅地计算结果

结果实现所需的时间比使用<
#include <opencv2/opencv.hpp>

void structure_tensor(cv::Mat const& img, cv::Mat& E, cv::Mat& F, cv::Mat& G)
{
    // Load and convert to Lab (keeping the raw lab values by using 32F matrix)
    cv::Mat lab;
    img.convertTo(lab, CV_32F, 1 / 255.0);
    cv::cvtColor(lab, lab, cv::COLOR_BGR2Lab);

    // Compute derivatives in both directions 
    cv::Mat dx, dy;
    cv::Sobel(lab, dx, CV_32F, 1, 0, 3);
    cv::Sobel(lab, dy, CV_32F, 0, 1, 3);

    E.create(lab.size(), CV_32FC1);
    F.create(lab.size(), CV_32FC1);
    G.create(lab.size(), CV_32FC1);

    for (int r(0); r < lab.rows; ++r) {
        cv::Vec3f const* idx = dx.ptr<cv::Vec3f>(r);
        cv::Vec3f const* idy = dy.ptr<cv::Vec3f>(r);
        float* iE = E.ptr<float>(r);
        float* iF = F.ptr<float>(r);
        float* iG = G.ptr<float>(r);

        for (int c(0); c < lab.cols; ++c, ++idx, ++idy) {
            *iE++ = idx->dot(*idx);
            *iF++ = idx->dot(*idy);
            *iG++ = idy->dot(*idy);
        }

        /* Or like this, pick what you like more.
        for (int c(0); c < lab.cols; ++c) {
            iE[c] = idx[c].dot(idx[c]);
            iF[c] = idx[c].dot(idy[c]);
            iG[c] = idy[c].dot(idy[c]);
        }
        */
    }
}

int main()
{
    // Make some random data
    cv::Mat img(16, 16, CV_8UC3);
    cv::randu(img, 0, 256);

    cv::Mat E, F, G;

    structure_tensor(img, E, F, G);

    return 0;
}