I need to construct a gaussian filter using C++. I am successfully getting my pixels from the image and constructing both grids; the one with 1 in the center and the one with one in the corner, my problem is I don't quit understand the gaussian equation! what should I put in the pixel that I should put in the output Image?? What should I put in else? Should I sum all the pixels from the modified grid (The one with 1 in the corner) or what?
for ( int r = 0; r < rowCt; r++ )
{
for ( int c = 0; c < colCt; c++ )
{
getPixel ( r, c, onePix );// geting pixel from the Img
int index = getIndex(r,c);// change colomns and rows to one dimentional array
if(c <= (f/2) || c >= colCt-((f/2)-1)-1 || r >= rowCt-((r/2)-1)-1 || r <= ((r/2)-1))
onePix = 0;// black if in the border
else
{
.... // ??
}
outIm.setPixel ( r, c, outPut_Pixel);
}
}
}
Related
I'm trying to cycle through the RGB spectrum smoothly, but so far I've only been able to make code that either goes through 768 colors (256*3) smoothly or goes through 16777216 colors (256^3) with discrete jumps.
Here's the code that runs smoothly:
void loop() {
setColor(255,0,0);
setColor(255,255,0);
setColor(0,255,0);
setColor(0,255,255);
setColor(0,0,255);
setColor(255,0,255);
}
void setColor(int red, int green, int blue) {
while ( r != red ) {
if ( r < red ) r += 1;
if ( r > red ) r -= 1;
_setColor();
delay(10);
}
while ( g != green){
if ( g < green ) g += 1;
if ( g > green ) g -= 1;
_setColor();
delay(10);
}
while ( b != blue){
if ( b < blue ) b += 1;
if ( b > blue ) b -= 1;
_setColor();
delay(10);
}
}
void _setColor() {
analogWrite(redPin, r);
analogWrite(greenPin, g);
analogWrite(bluePin, b);
}
Here's the code that runs through every RGB value:
void loop() {
for (r = 0; r <= 255; r++) {
for (g = 0; g <= 255; g++) {
for (b = 0; b <= 255; ++) {
analogWrite(redPin, r);
analogWrite(greenPin, g);
analogWrite(bluePin, b);
}
}
}
The smooth code will never combine values in between the max/min of the colors, i.e. I never get anything like [128,64,72], only outputs like [255,64,0] or [0,0,72].
The discrete code runs through every blue value, then increases the green value, and starts back at 0 for blue, i.e. [0,0,254] -> [0,0,255] -> [0,1,0] -> [0,1,1] which creates discrete jumps.
I'm trying to get a smooth cycle which goes through every possible RGB value, is that even possible?
Sure you can visit every point in a 256^3 space continuously.
The easiest way is to start with a line, then turn a line into a plane, then turn a plane into a cube.
struct simple_generator {
int current = 0;
int min = 0;
int max = 255;
int direction = 1;
bool advance() // returns false iff we hit the end
{
if (current + direction > max || current+direction < min) {
direction = -direction;
return false;
}
current += direction;
return true;
}
};
now let's make a generator from this.
template<std::size_t N>
struct shape_generator {
simple_generator state[N];
int operator[](std::size_t i) const { return state[i].current; }
bool advance() {
for (std::size_t i = 0; i < N; ++i) {
if (state[i].advance())
return true;
}
return false;
}
};
now what this does it advances the first simple generator until it overflows (which causes the generator stand still and reverse directions). If it overflows, it "recursively" advances the next one.
If every generator overflows, it returns false. Otherwise it returns true.
This will generate a pretty boring curve, as it mostly looks like "blue goes to top, then back down, back to top, and back down". Only after many cycles does any green show up. And only after many cycles of green does any red show up.
A fancier one would use an approximation of a real space-filling curve, like the Hilbert curve. But that should work
Live example with a max of 5, because running it for 256^3 elements seems rude.
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[X-Y 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:
Currently I am working on paralizing an image processing algorithm to extract edges from a given image. I recently started with code parallelizing.
Anyway a part of the program requires me to compute the histogram of the image and count the number of occurding pixels from 1 to its maximum gradient Intensity.
I have implemented it as the following:
tbb::concurrent_vector<double> histogram(32768);
tbb::parallel_for(tbb::blocked_range<size_t>(1, width - 1),
[&](const tbb::blocked_range<size_t>& r)
{
unsigned int idx;
for (size_t w = r.begin(); w != r.end(); ++w) //1 to (width -1)
{
for (size_t h = 1; h < height - 1; ++h)
{
idx = h * width + w;
//DO SOME STUFF BEFORE
//Get max gradient intensity
if (pgImg[idx] > maxGradIntensity)
{
maxGradIntensity = pgImg[idx];
}
//Get histogram information
if (pgImg[idx] > 0)
{
tbb::mutex::scoped_lock sync(locked);
++histogram[(int)pgImg[idx]];
++totalGradPixels;
}
}
}
});
histogram.resize(maxGradIntensity);
So the part where it becomes tricky for me is the following:
if (pgImg[idx] > 0)
{
tbb::mutex::scoped_lock sync(locked);
++histogram[(int)pgImg[idx]];
++totalGradPixels;
}
How can I avoid using tbb::mutex? I had no luck with setting the vector to tbb::atomic. Maybe I did something wrong there. Any help on this topic would be appreciated.
How to get all objects from image i am separating image objects through colors.
There are almost 20 colors in following image. I want to extract all colors and their position in a vector(Vec3b and Rect).
I'm using egbis algorithum for segmentation
Segmented image
Mat src, dst;
String imageName("/home/pathToImage.jpg" );
src = imread(imageName,1);
if(src.rows < 1)
return -1;
for(int i=0; i<src.rows; i=i+5)
{ for(int j=0; j<src.cols; j=j+5)
{
Vec3b color = src.at<Vec3b>(Point(i,j));
if(colors.empty())
{
colors.push_back(color);
}
else{
bool add = true;
for(int k=0; k<colors.size(); k++)
{
int rmin = colors[k].val[0]-5,
rmax = colors[k].val[0]+5,
gmin = colors[k].val[1]-5,
gmax = colors[k].val[1]+5,
bmin = colors[k].val[2]-5,
bmax = colors[k].val[2]+5;
if((
(color.val[0] >= rmin && color.val[0] <= rmax) &&
(color.val[1] >= gmin && color.val[1] <= gmax) &&
(color.val[2] >= bmin && color.val[2] <= bmax))
)
{
add = false;
break;
}
}
if(add)
colors.push_back(color);
}
}
}
int size = colors.size();
for(int i=0; i<colors.size();i++)
{
Mat inrangeImage;
//cv::inRange(src, Scalar(lowBlue, lowGreen, lowRed), Scalar(highBlue, highGreen, highRed), redColorOnly);
cv::inRange(src, cv::Scalar(colors[i].val[0]-1, colors[i].val[1]-1, colors[i].val[2]-1), cv::Scalar(colors[i].val[0]+1, colors[i].val[1]+1, colors[i].val[2]+1), inrangeImage);
imwrite("/home/kavtech/Segmentation/1/opencv-wrapper-egbis/images/inrangeImage.jpg",inrangeImage);
}
/// Display
namedWindow("Image", WINDOW_AUTOSIZE );
imshow("Image", src );
waitKey(0);
I want to get each color position so that
i can differentiate object positions. Please Help!
That's just a trivial data formatting problem. You want to turn a truecolour image with only 20 or so colours into a colour-indexed image.
So simply step through the image, look up the colour in your growing dictionary, and assign and integer 0-20 to each pixel.
Now you can turn the images into binary images simply by saying one colour is set and the rest are clear, and use standard algorithms for fitting rectangles.
I am trying to write an algorithm for a program to draw an even, vertical gradient across an image. I.e. I want change the pixel color from 0 to 255 along the m rows of an image, but cannot find a good generic algorithm to do so.
I've tried to implement something like this using opencv, but it does not seem to work
#include <opencv2/opencv.hpp>
int main(){
//Make the image white.
cv::Mat Img(w_height, w_width, CV_8U);
for (int y = 0; y < Img.rows; y += 1) {
for (int x = 0; x < Img.cols; x++) {
Img.at<uchar>(y, x) = 255;//White
}
}
// try to create an even, vertical gradient
for(int row = 0; row < Img.rows; row++ ){
for(int col = 0; col < Img.cols; col++){
Img.at<uchar>(row, col) = col % 256;
}
}
cv::imshow("Window", Img);
cv::waitKey(0);
return 0;
}
Solving this problem requires the knowledge of three simple tricks:
1. Interpolation:
The process of gradually changing from one value to another is called interpolation. There are multiple ways of interpolating color values: the simplest one is to interpolate each component linearly, i.e. in the form of:
interpolated = start * (1-t) + dest * t.
Where
start is the value you are interpolating from towards the value dest.
t denotes how close the interpolated value should be to the destination value dest on a scale of 0 to 1 with 0 being the pure start color and 1 being the pure dest color.
You will find that linear interpolation in the RGB color space doesn't produce natural color paths. As an advanced step, you could utilise the HSV color space instead. See this question for further information about color interpolation.
2. Discretisation:
Unfortunately, interpolation produces real numbers. Thus, we have to discretise them to be able to use them as integer color values. The best way to do this is to round to the nearest integer by using e.g. round() in C++.
3. Finding the interpolation point:
Now, we just need a real-valued interpolation point t at each row of our image. We can deduce a formula for this by analysing what output we want to see:
For the bottommost row (row 1) we want to have t == 0 since that is where we want our pure start color to appear.
For the topmost row (row m) we want to have t == 1 since that is where we want the pure destination color to appear.
For every other row we want t to scale linearly with the distance to the bottommost row.
A formula to achieve this result is:
t = rowIndex / m
The approach can readily be adapted to other gradient directions by changing this formula appropriately.
Sample code (using linear interpolation, C++):
#include <algorithm>
#include <cmath>
Color interpolateRGB(Color from, Color to, float t)
{
// Clamp __t__ to range [0,1]
t = std::max(std::min(0.f, t), 1.f);
// Interpolate each RGB component
uint8_t r = std::roundf(from.r * (1-t) + to.r * t);
uint8_t g = std::roundf(from.g * (1-t) + to.g * t);
uint8_t b = std::roundf(from.b * (1-t) + to.b * t);
return Color(r, g, b);
}
void fillWithGradient(Image& img, Color from, Color to)
{
for(size_t row = 0; row < img.numRows(); ++row)
{
Color value = interpolateRGB(from, to, row / (img.numRows()-1));
// Set all pixels of this row to __value__
for(size_t col = 0; col < img.numCols(); ++col)
{
img.setPixel(row, col, value);
}
}
}
The basic idea would be to use the remainder of the division r of n/(m-1) and adding it to n on each iteration:
#include <iostream>
#include <vector>
using namespace std;
vector<int> gradient( int n, int m ) {
div_t q { 0, 0 };
vector<int> grad(m);
for( int i=1 ; i<m ; ++i ) {
q = div( n + q.rem, m-1 );
grad[i] = grad[i-1] + q.quot;
}
return grad;
}
int main() {
for( int i : gradient(255,10) ) cout << i << ' ';
cout << '\n';
return 0;
}
Output:
0 28 56 85 113 141 170 198 226 255