How to set given channel of a cv::Mat to a given value efficiently without changing other channels?

后端 未结 4 804
走了就别回头了
走了就别回头了 2020-12-11 01:12

How to set given channel of a cv::Mat to a given value efficiently without changing other channels? For example, I want to set its fourth channel (alpha channel

相关标签:
4条回答
  • 2020-12-11 01:48

    If your image is continuous in memory you can use following trick:

    mat.reshape(1,mat.rows*mat.cols).col(3).setTo(Scalar(120));
    

    If it is not continuous:

    for(int i=0; i<mat.rows; i++)
        mat.row(i).reshape(1,mat.cols).col(3).setTo(Scalar(120));
    

    Edit (thanks to Antonio for the comment):

    Note that this code may be the shortest and it is not allocating new memory but it is not efficient at all. It may be even slower than split/merge approach. OpenCV is really inefficient when it should perform operations on non-continuous matrices with 1 pixel in a row. If time performance is important you should use the solution proposed by @Antonio.

    Just a minor improvement to his solution:

    const int cols = img.cols;
    const int step = img.channels();
    const int rows = img.rows;
    for (int y = 0; y < rows; y++) {
        unsigned char* p_row = img.ptr(y) + SELECTED_CHANNEL_NUMBER; //gets pointer to the first byte to be changed in this row, SELECTED_CHANNEL_NUMBER is 3 for alpha
        unsigned char* row_end = p_row + cols*step;
        for(; p_row != row_end; p_row += step)
             *p_row = value;
        }
    }
    

    This saves increment operation for x and one less value in register. On system with limited resources it may give ~5% speedup. Otherwise time performance will be the same.

    0 讨论(0)
  • 2020-12-11 01:53

    What about direct Mat::data access (I'm quite sure setTo() or oother opencv Mat api use similar solution):

    template<int N>
    void SetChannel(Mat &img, unsigned char newVal) {   
        for(int x=0;x<img.cols;x++) {
            for(int y=0;y<img.rows;y++) {
                *(img.data + (y * img.cols + x) * img.channels() + N) = newVal;
            }
        }
    }
    
    
    int main() {
        Mat img = Mat::zeros(1000, 1000, CV_8UC4);
        SetChannel<3>(img, 120);
        imwrite("out.jpg", img);
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-11 01:58
    Mat img;
    [...]
    const int cols = img.cols;
    const int step = img.channels();
    const int rows = img.rows;
    for (int y = 0; y < rows; y++) {
        unsigned char* p_row = img.ptr(y) + SELECTED_CHANNEL_NUMBER; //gets pointer to the first byte to be changed in this row, SELECTED_CHANNEL_NUMBER is 3 for alpha
        for (int x = 0; x < cols; x++) {
             *p_row = value;
             p_row += step; //Goes to the next byte to be changed
        }
    }
    

    Note: This works both for continuous and uncontinuous matrices, according to the use of the term for opencv: http://docs.opencv.org/modules/core/doc/basic_structures.html#bool%20Mat::isContinuous%28%29%20const

    0 讨论(0)
  • 2020-12-11 02:05

    Simple algorithm:

    void SetChannel(Mat mat, uint channel, uchar value)
    {
        const uint channels = mat.channels();
        if (channel > channels - 1)
            return;
    
        uchar * data = mat.data;
        uint N = mat.rows * mat.step / mat.elemSize1();
    
        for (uint i = channel; i < N; i += channels)
            data[i] = value;
    }
    
    0 讨论(0)
提交回复
热议问题