How can I copy elements from one type of Mat to a different type of Mat

I am trying to copy 16 bit monochrome values (16UC1) to the blue and green channels of an 8UC3 mat.
The commented lines will do what I want but involve several math operations per pixel. It should be faster to directly copy the 16 bit value to the two (adjacent in memory) 8 bit color channels.
The line: “pdst[j] = psrc[j];” compiles without warnings or errors but only seems to copy one byte. Is there a way to apply a static_cast or other mechanism to trick the compiler into doing what I want? This is getting into C++ that is way over my head.

            cv::Mat BGRframe(grayframe.size(),CV_8UC3);         // Create output frame, same size as input but with 3 8-bit channels
            // work out geometry of roi in memory
            int nRows = grayframe.rows;
            int nCols = grayframe.cols;

            if (grayframe.isContinuous()) {
                nCols *= nRows;
                nRows = 1;

            // iterate through the input frame, pixel by pixel, copying each word into 2 channels
            for (int i = 0; i < nRows; ++i) {
                cv::Vec3b* pdst = BGRframe.ptr<cv::Vec3b>(i);                       //pointer to a row of the output frame
                const unsigned short * psrc = grayframe.ptr<unsigned short>(i);		//pointer to a row of input

                for (int j = 0; j < nCols; ++j) {
//                    pdst[j].val[0] = (psrc[j]/256) & 0x00FF;     // Put upper 8 bits of each 16 bit pixel in Blue Channel
//                    pdst[j].val[1] = psrc[j] & 0x00FF;           // Put lower 8 bits of each 16 bit pixel in Green Channel
                    pdst[j] = psrc[j];                           // Put 16 bits into adjacent Blue and Green Channels
                    pdst[j].val[2] = 0;                          // Set Red channel to 0 to minimize compressed size. (Could use for meta data?)

the problem is that you have 8UC3, so the two (of three) channels you’re trying to assign to aren’t contiguous. a bunch of copying will be required.

OpenCV Mats don’t have a stride between elements, only between rows. that makes them somewhat inflexible. even the Mat constructors that do take a steps argument only take the outermost D-1 steps because the innermost one is always 1.

you are better off holding those three planes as separate matrices, then using merge() afterwards.

if you have to touch individual pixels, you can try to access the 16U Mat using at<uint8_t>() (or Vec2b). it’s all just pointer arithmetic and casts underneath.

you can also make a temporarily created Mat that uses the same memory (data pointer) as the 16U one, but assumes 8UC2. then you could apply split (and copyTo, or just use those planes in a merge directly)

Thank you for the explanation. It’s clear this is going to be harder than I hoped. I need to do some more thinking! The frames are relatively small so maybe I can get away with the original commented out solution.