C++ 中类似 Python 的切片操作

Posted

技术标签:

【中文标题】C++ 中类似 Python 的切片操作【英文标题】:Python like Slicing operation in c++ 【发布时间】:2020-07-27 19:53:43 【问题描述】:

我有以下代码,其中 'Snap.JPG' 是 RGB 格式类型。

import cv2

img = cv2.imread("./Snap.JPG")

img[:,:,:2] = 255

cv2.imshow("Img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

我想将此代码转换为 c++。实现img[:,:,:2] = 255部分代码的最快方法是什么?通道拆分和合并是我知道的选项之一,但是有没有更聪明的方法可以在 c++ 中进行切片?

编辑: 抱歉,我应该在输出中提到我想要的。我需要一个淡入淡出的效果,因为我想在它上面叠加一张图。

【问题讨论】:

您能举例说明img[:,:,:2] 的作用吗? 我认为它的计算结果是一个左值表达式。 由于涉及副本,拆分和合并肯定不是最佳的。编译器应该能够优化所有元素的简单循环,您只覆盖Vec3b 的前两个部分。然后可能将其转换为 cv::ParallelLoopBody 的派生类,以便您可以使用 cv::parallel_for_... 运行它...或者这些天 lambda 也可以。 @cigien,我猜它会将所有ijk = 0, 1 设置为img[i, j, k] @cigien 它为仅包含前两个通道的原始数组创建了一个视图。然后将 255 分配给第一个和第二个通道中的所有值。鉴于图像是 BGR(它是 OpenCV),这意味着图像中所有像素的所有蓝色和绿色强度都设置为 255。 【参考方案1】:

这是一个如何改变像素的例子:

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

int main(int argc, char** argv) 
    cv::Mat src_image = cv::imread("image.jpg", CV_LOAD_IMAGE_COLOR);

    if(!src_image.data) 
        std::cout << "Error: the image wasn't correctly loaded." << std::endl;
        return -1;
    

    cv::Mat image = src_image.clone();

    // We iterate over all pixels of the image
    for(int r = 0; r < image.rows; r++) 
        // We obtain a pointer to the beginning of row r
        cv::Vec3b* ptr = image.ptr<cv::Vec3b>(r);

        for(int c = 0; c < image.cols; c++) 
            ptr[c] = cv::Vec3b(255, 255, ptr[c][2]);
        
    

    cv::imshow("Inverted Image", image);
    cv::waitKey();

    return 0;

【讨论】:

【参考方案2】:

感谢@Manuel 的回复,效果很好。但我可以用更快的速度达到同样的效果。我已经添加了我的代码 sn-ps inline 你的代码。

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <iomanip>


int main(int argc, char** argv) 
    clock_t start, end;

    cv::Mat src_image = cv::imread("Snap.JPG", CV_LOAD_IMAGE_COLOR);

    if(!src_image.data) 
        std::cout << "Error: the image wasn't correctly loaded." << std::endl;
        return -1;
    

    /* 1st method */
    cv::Mat image = src_image.clone();

    start = clock();
    // We iterate over all pixels of the image
    for(int r = 0; r < image.rows; r++) 
        // We obtain a pointer to the beginning of row r
        cv::Vec3b* ptr = image.ptr<cv::Vec3b>(r);

        for(int c = 0; c < image.cols; c++) 
            ptr[c] = cv::Vec3b(255, 255, ptr[c][2]);
        
    
    end = clock();

    double time_taken = double(end - start) / double(CLOCKS_PER_SEC);
    std::cout << "Time taken by 1st method : " << std::fixed << time_taken << std::setprecision(5);
    std::cout << " sec " << std::endl;

    /* 2nd Method */
    start = clock();
    src_image = src_image | cv::Scalar(255, 255, 0);
    end = clock();

    time_taken = double(end - start) / double(CLOCKS_PER_SEC);
    std::cout << "Time taken by 2nd method : " << std::fixed << time_taken << std::setprecision(5);
    std::cout << " sec " << std::endl;

    bool isEqual = (sum(src_image != image) == cv::Scalar(0,0,0,0));
    if (isEqual)
    
        std::cout << "\nIdentical Mats !" << std::endl;
    

    cv::imshow("Inverted Image", image);
    cv::waitKey();

    return 0;

输出如下:

Time taken by 1st method : 0.001765 sec
Time taken by 2nd method : 0.00011 sec

Identical Mats !

【讨论】:

以上是关于C++ 中类似 Python 的切片操作的主要内容,如果未能解决你的问题,请参考以下文章

Python中numpy 数组的切片操作

在 C++ 中切片 char 数组(python 到 c++)

C++ 相当于 Python 字符串切片?

golang基础---Slice切片

python学习DAY3(列表)

Python学习篇 Python中的列表