简体   繁体   中英

Incorrect Pattern Image Generation in OpenCV

Content: Image Processing in OpenCV C++.

The Requirement is to create tiles of Mat pattern of size 256 X 256 on an outer Mat Image. The user specifies the width and the height of the outer Mat Image.

To do this , I created the below OpenCV C++ function:

Mat GenerateDiagonalFade(int width, int height)
{

// Creating a Mat Image in user defined dimension
Mat image(height, width, CV_8UC1, Scalar(0)); 


//Looping through all rows and columns of the outer Image
for (int row = 0; row < image.rows; row ++)
{
    for (int col = 0; col < image.cols; col ++)
    {   

       //Here, I am giving the condition to access the pixel values

       //The pattern should be 255 X 255 and they must fill in the entire image

        if ((row % 256 + col % 256) <= 255)
        {

            image.at<uchar>(row, col) = (row % 256 + col  % 256);
        }

        else
        {
            //Here is where I get error
            image.at<uchar>(row, col) = abs(row % 256 - col % 256);
        }
    }
}
return image;
}

If you can see the else statement above, I tried to make the inverse of the first condition and make the value absolute.

The output I get is as seen below: 在此处输入图片说明

The Expected Output is the inverse of the first part of the diagonal. Darker to lighter shade towards the diagonal.

I tried replacing abs(row % 256 - col % 256); with many statements. I am struct with the output. The changes should be made only in the else statement. Rest of my code is correct as half of my output( top diagonal) is right.

I appreciate any help from you in order to solve this. Trust me, it's quite interesting to work out all graphical[XY axis] and mathematical calculations[pixel access] to get the desired output.

I would begin by splitting the problem into two parts:

  • Generating a single tile containing the correct pattern
  • Using that tile (or algorithm) to generate the whole image

Generating a Tile

The goal is to generate a 256x256 grayscale image containing a gradient such that:

  • Top left corner is all black
  • Bottom right corner is all black
  • The diagonal going from bottom left to top right is all white

You got the part above the diagonal right, but let's inspect that anyway.

The coordinates of the top left corner are (0, 0) and we expect intensity of 0. --> row + col == 0

The coordinates of one end of the diagonal are (255, 0) and we expect intensity of 255. --> row + col == 255

The other end of the diagonal is at (0, 255) -> row + col == 255

Let's try another point on the diagonal, (254,1) --> again row + col == 255

OK, now a point just above the diagonal, (254,0) -> row + col == 254 -- slightly less white, as we would expect.

Next, let's try a point just below the diagonal, say (255, 1) --> row + col == 256 . If we cast this to an 8 bit integer, we get a 0, yet we expect 254, just like in the previous case.

Finally, bottom right corner (255, 255) -> row + col == 510 . If we cast this to an 8 bit integer, we get a 254, yet we expect 0.

Let's try something:

  • 256 + 254 == 510
  • 510 + 0 == 510

And we see an algorithm: * If the sum of row + col is less than 256, then use the sum * Otherwise subtract the sum from 510 and use the result

Sample code:

cv::Mat make_tile()
{
    int32_t const TILE_SIZE(256);
    cv::Mat image(TILE_SIZE, TILE_SIZE, CV_8UC1);
    for (int32_t r(0); r < TILE_SIZE; ++r) {
        for (int32_t c(0); c < TILE_SIZE; ++c) {
            int32_t sum(r + c);
            if (sum < TILE_SIZE) {
                image.at<uint8_t>(r, c) = static_cast<uint8_t>(sum);
            } else {
                image.at<uint8_t>(r, c) = static_cast<uint8_t>(2 * (TILE_SIZE - 1) - sum);
            }            
        }
    }
    return image;
}

Single tile:

单瓦


Generating Image of Tiles

Now that we have a complete tile, we can simply generate the full image by iterating over tile-sized ROIs of the target image, and copying a tile ROI of identical size to them.

Sample code:

#include <opencv2/opencv.hpp>
#include <cstdint>

cv::Mat make_tile()
{
    int32_t const TILE_SIZE(256);
    cv::Mat image(TILE_SIZE, TILE_SIZE, CV_8UC1);
    for (int32_t r(0); r < TILE_SIZE; ++r) {
        for (int32_t c(0); c < TILE_SIZE; ++c) {
            int32_t sum(r + c);
            if (sum < TILE_SIZE) {
                image.at<uint8_t>(r, c) = static_cast<uint8_t>(sum);
            } else {
                image.at<uint8_t>(r, c) = static_cast<uint8_t>(2 * (TILE_SIZE - 1) - sum);
            }            
        }
    }
    return image;
}

int main()
{   
    cv::Mat tile(make_tile());

    cv::Mat result(600, 800, CV_8UC1);

    for (int32_t r(0); r < result.rows; r += tile.rows) {
        for (int32_t c(0); c < result.cols; c += tile.cols) {
            // Handle incomplete tiles
            int32_t end_r(std::min(r + tile.rows, result.rows));
            int32_t end_c(std::min(c + tile.cols, result.cols));
            // Get current target tile ROI and source ROI of same size
            cv::Mat target_roi(result(cv::Range(r, end_r), cv::Range(c, end_c)));
            cv::Mat source_roi(tile(cv::Range(0, target_roi.rows), cv::Range(0, target_roi.cols)));
            // Copy the tile
            source_roi.copyTo(target_roi);
        }
    }

    cv::imwrite("gradient.png", tile);
    cv::imwrite("gradient_big.png", result);
}

Complete image:

完整图片

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM