patterncppMinor
Replace subimage by its average value
Viewed 0 times
subimagereplaceaveragevalueits
Problem
I have the input image
Here is my brute force approach. I'm wondering if there is any better way of doing it.
P/S:
Here is an example.
Input Image:
Mask image, it is basically a matrix labelling the pixels into one of 4 categories
Output picture is the average of input image, for each category of pixels. For example, at first I find all pixels has category 1, find their average, and replace all those pixels by the average value.
in, and the mask image lev (which label each pixel as a number from 1 to nlevels, nlevels=4). I need to get image out, which from each region in==lev will be replaced by its average value.Here is my brute force approach. I'm wondering if there is any better way of doing it.
Mat ACA::global_average(Mat in, const Mat &lev)
{
// in: CV_32F
// lev: CV_32S
int M=in.rows;
int N=in.cols;
in.convertTo(in, CV_32FC3);
// vector holds average value for each category
vector count(nlevels,0);
vector average(nlevels);
int pixlev;
for (int i=0; i (i,j);
assert (pixlev(i,j);
count[pixlev]++;
}
for (int i=0; i(i,j);
out.at(i,j)=average[pixlev];
}
return out;
}P/S:
Here is an example.
Input Image:
Mask image, it is basically a matrix labelling the pixels into one of 4 categories
Output picture is the average of input image, for each category of pixels. For example, at first I find all pixels has category 1, find their average, and replace all those pixels by the average value.
Solution
Algorithm
You will benefit greatly from using OpenCV's built-in functionality rather than performing this operation yourself. OpenCV supports masked operations, which will only apply to pixels where the mask is nonzero.
Using functionality already present in OpenCV is not only clearer and shorter (by a factor of 3), but also allows the code to be more flexible. You will notice:
Code Style
Whitespace
Put spaces around your assignments and comparisons:
Braces
You have nested
Precondition Checking
Although it is good that you leave comments indicating the data types you expect from
Use
Both
You will benefit greatly from using OpenCV's built-in functionality rather than performing this operation yourself. OpenCV supports masked operations, which will only apply to pixels where the mask is nonzero.
cv::Mat global_average(const cv::Mat& input, const cv::Mat& levels)
{
assert(levels.channels() == 1);
cv::Mat output(input.size(), input.type());
for (int level = 0; level < nlevels; ++level)
{
const cv::Mat mask = levels == level;
const cv::Scalar avg = cv::mean(input, mask);
output.setTo(avg, mask);
}
return output;
}Using functionality already present in OpenCV is not only clearer and shorter (by a factor of 3), but also allows the code to be more flexible. You will notice:
- There is no explicit type conversion or array indexing occurring, which is safer.
- This code is also more flexible: you do not need to convert your images to floating-point or integers.
- It can operate on 8-bit images as well, which can give a significant speedup, since most of the time in the algorithm will be spent on memory access. Simply using the raw 8-bit images gives a ~15% speedup in my tests.
- It is also possible that OpenCV functions may benefit from hardware and parallelism optimizations, which could make them faster than raw loops.
Code Style
Whitespace
Put spaces around your assignments and comparisons:
int i=0; i<m; is harder to read than int i = 0; i < M;. Also, be consistent. Sometimes you do this already, but most of the time you do not.Braces
You have nested
for loops, but only the inner loop has braces. Both loops should have braces surrounding the body for consistency.Precondition Checking
Although it is good that you leave comments indicating the data types you expect from
in and lev, it is better to verify this in code. Adding assertions about these conditions makes it easier to debug if a wrong parameter is passed:assert(in.depth() == CV_32F);
assert(lev.depth() == CV_32S);Use
const when you canBoth
M and N do not change during the function evaluation. They can be declared as const int to allow the compiler to perform checks that they are never accidentally modified. Additionally, you can reduce the scope of pixlev by declaring it inside each of the loops. Then it too can be made const:const int pixlev = lev.at(i,j); // or use auto to reduce type duplicationCode Snippets
cv::Mat global_average(const cv::Mat& input, const cv::Mat& levels)
{
assert(levels.channels() == 1);
cv::Mat output(input.size(), input.type());
for (int level = 0; level < nlevels; ++level)
{
const cv::Mat mask = levels == level;
const cv::Scalar avg = cv::mean(input, mask);
output.setTo(avg, mask);
}
return output;
}assert(in.depth() == CV_32F);
assert(lev.depth() == CV_32S);const int pixlev = lev.at<int>(i,j); // or use auto to reduce type duplicationContext
StackExchange Code Review Q#36656, answer score: 6
Revisions (0)
No revisions yet.