OpenCV - Can't access all pixels in a Mat - ios

I'm trying to manually change every pixel in a Mat.
For simplicity reasons, let's say I want to color each pixel black. I'm using the following method:
for (int i = 0; i < imageToWorkWith.rows; i++) {
for (int j = 0; j < imageToWorkWith.cols; j++) {
imageToWorkWith.at<cv::Vec3b>(i,j) = cv::Vec3b(0,0,0);
}
}
Logically, it seems like this should go over every pixel in the mat, as it reads all the possible combinations of row/col.
Unfortunately, this doesn't work. For every image, I'm missing a "chunk" of columns. For example, when loading this image:
The result is this:
This "chunk" I'm missing is the same size, no matter what image I use. I can't seem to understand the reason for that. I know that the order of row/col for the "at" function is (row, col), but i tried switching them just for kicks, and the result of course is even worse.
What am I missing here? is looping over all rows/cols not enough?

Just use Vec4b instead of Vec3b as the image by default is having 4 channels in ios. The result will be full white.
for (int i = 0; i < imageToWorkWith.rows; i++) {
for (int j = 0; j < imageToWorkWith.cols; j++) {
imageToWorkWith.at<cv::Vec4b>(i,j) = cv::Vec4b(0,0,0);
}
}

Related

Compute shader hangs when setting two pixels while looping RWTexture2D (DirectX11, SM5)

I'm trying to perform some basic cellular automata on compute shader (DirectCompute) but without double buffering, so I'm using unordered access view to a RWTexture2D<uint> for the data, however I'm having some really strange hang/crash here, I could make a very small snippet that produces the issue:
int w = 256;
for (int x = 0; x < w; ++x)
{
for (int y = 1; y < w; ++y)
{
if (map[int2(x, y - 1)])
{
map[int2(x, y)] = 10;
map[int2(x, y-1)] = 30;
}
}
}
where map is RWTexture2D<uint>.
If I remove the if or one of the assignments, it works, I thought it could be some kind of limit so I tried looping just 1/4 of the texture but the problem persists. That code is dispatched with (1,1,1) and kernel numthreads is (1,1,1) too, in my real-world scenario I want to loop from bottom to top and fill the voids (0) with the pixel I'm currently looping (think of a "falling sand" kind of effect), so it can't be parallel except in columns since it depends on the bottom pixel.
I don't understand what is causing the shader to hang though, there's no error or anything, it simply hangs and never not even times out.
EDIT:
After some further investigation, I came across something really intriguing; when I pass that w value in a constant buffer it all works fine. I have no idea what would cause that, maybe it's some compiling optimization that went wrong, maybe it tries to unroll the loop what causes some issue, and passing the value in a constant buffer disables that, however I'm compiling the shaders in debug with no optimization so I don't know.
I've had issues declaring variables in global scope like this before. I believe it's because it's not static const (so declare as a static const and it should work). Most likely, it's treating it as a constant buffer (with some default naming) and the contents are undefined since you're not binding a buffer, which causes undefined results. So the following code should work:
static const int w = 256;
for (int x = 0; x < w; ++x)
{
for (int y = 1; y < w; ++y)
{
if (map[int2(x, y - 1)])
{
map[int2(x, y)] = 10;
map[int2(x, y-1)] = 30;
}
}
}

OpenCV MultiBandBlender doesn't work

I try to blend my images into pano with MultiBandBlender, but it return black pano. But FeatherBlender works fine. What I doing wrong?
blendImages(const std::vector<cv::Point> &corners, std::vector<cv::Mat> images)
{
std::vector<cv::Size> sizes;
for(int i = 0; i < images.size(); i++)
sizes.push_back(images[i].size());
float blend_strength = 5;
cv::Size dst_sz = cv::detail::resultRoi(corners, sizes).size();
float blend_width = sqrt(static_cast<float>(dst_sz.area())) * blend_strength / 100.f;
cv::Ptr<cv::detail::Blender> blender = cv::detail::Blender::createDefault(cv::detail::Blender::MULTI_BAND);
//cv::detail::FeatherBlender* fb = dynamic_cast<cv::detail::FeatherBlender*>(blender.get());
//fb->setSharpness(1.f/blend_width);
cv::detail::MultiBandBlender* mb = dynamic_cast<cv::detail::MultiBandBlender*>(blender.get());
mb->setNumBands(static_cast<int>(ceil(log(blend_width)/log(2.)) - 1.));
blender->prepare(corners, sizes);
for(int i = 0; i < images.size(); i++)
{
cv::Mat image_s;
images[i].convertTo(image_s, CV_16SC3);
blender->feed(image_s, cv::Mat::ones(image_s.size(), CV_8UC1), corners[i]);
}
cv::Mat pano;
cv::Mat panoMask = cv::Mat::ones(dst_sz, CV_8UC1);
blender->blend(pano, panoMask);
return pano;
}
Three possible causes:
Try keeping all image_s and masks in a vector, and feed with the following structure:
for (int i = 0; i < images_s.size(); ++i)
blender->feed(images_s[i], masks[i], corners[i]);
Don't initialize panoMask to ones before blending.
Make sure corners are well defined
Actually, I can't compile your code with OpenCV 2.4, because of blender.get function. There is no such a function in my build of OpenCV 2.4.
Anyway, if you wish to make a panorama, you'd better not use resultRoi function. You need boundingRect. I suppose, it is really hard to get all horizontally aligned images for one panorama.
Also, look at my answer here. It demonstrates how to use MultiBandBlender.
Hey I was getting the same black pano while using MultiBand blender in opencv. Actually the issue was resolved by changing
cv::Mat::ones(image_s.size(), CV_8UC1)
to
cv::Mat::ones(image_s.size(), CV_8UC1)*255
This is because Mat::ones initialize all the pixels to a value of numerical 1, Thus, we need to muliply it with 255 in order to get a pure black & white mask.
And, thanks, your issue solved my problem :)

Confusion analyzing blobs using contours

I want to analyze the blobs received using contours. However, I came across with a slight problems where is there any difference analyzing the blobs before and after using the following code?
for(unsigned int i = 0; i < rects3.size(); i++) {
Scalar color = Scalar(255,255,255);
drawContours( drawing3, contours3, i, color, CV_FILLED, 8);
}
before using the above, there are only some boundaries line and after using the code we can see the white blobs. As attached are the example of it.
You want to iterate through the possible blobs and then analyze it (area, perimeter, etc).
Your contours are in vector called rects3.
// iterating trough
for(unsigned int i = 0; i < rects3.size(); i++) {
// get the bounding box of one contour
Rect rect = boundingRect(rects3[i]);
//area
double area = contourArea(rects3[i]);
//perimiter
double perimiter = arcLength(rects3[i], true);
}
see http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html

Column sum of Opencv Matrix elements

I need to compute sum of elements in all columns separately.
Now I'm using:
Matrix cross_corr should be summed.
Mat cross_corr_summed;
for (int i=0;i<cross_corr.cols;i++)
{
double column_sum=0;
for (int k=0;k<cross_corr.rows;k++)
{
column_sum +=cross_corr.at<float>(k,i);
}
cross_corr_summed.push_back(column_sum);
}
The problem is that my program takes quite a long time to run. This is one of parts that is suspicious to cause this.
Can you advise any possible faster implementation???
Thanks!!!
You need a cv::reduce:
cv::reduce(cross_corr, cross_corr_summed, 0, CV_REDUCE_SUM, CV_32S);
If you know that your data is continuous and single-channeled, you can access the matrix data directly:
int width = cross_corr.cols;
float* data = (float*)cross_corr.data;
Mat cross_corr_summed;
for (int i=0;i<cross_corr.cols;i++)
{
double column_sum=0;
for (int k=0;k<cross_corr.rows;k++)
{
column_sum += data[i + k*width];
}
cross_corr_summed.push_back(column_sum);
}
which will be faster than your use of .at_<float>(). In general I avoid the use of .at() whenever possible because it is slower than direct access.
Also, although cv::reduce() (suggested by Andrey) is much more readable, I have found it is slower than even your implementation in some cases.
Mat originalMatrix;
Mat columnSum;
for (int i = 0; i<originalMatrix.cols; i++)
columnSum.push_back(cv::sum(originalMatrix.col(i))[0]);

randomness from spritemap in spritebatch

Im sure this is easily fixed, and I do have searched both high and low, traversed the net both east, west, north and south but to no prevail...
My problem is this. Im in the middle of trying to make a bejeweled clone, just to get me started in xna. However im stuck on the random plotting of gems/icons/pictures.
This is what i have.
First a generated list of positions, a random and a rectangle:
List<Vector2> platser = new List<Vector2>();
Random slump = new Random();
Rectangle bildsourcen;
protected override void Initialize()
{
for (int j = 0; j < 5; j++)
{
for (int i = 0; i < 5; i++)
{
platser.Add(new Vector2((i*100),(j*100)));
}
}
base.Initialize();
}
Pretty straight-forward.
I also have loaded a texture, with 5 icons/gems/pictures -> 5*100px = width of 500px.
allImage = Content.Load<Texture2D>("icons/all");
Then comes the "error".
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
int x = slump.Next(2);
bildsourcen = new Rectangle((x * 100), 0, 100, 100);
for (int i = 0; i < platser.Count; i++)
{
spriteBatch.Draw(allImage, new Rectangle((int)platser[i].X, (int)platser[i].Y, 100, 100), bildsourcen, Color.White);
}
So, there is my code. And this is what happens:
I want it to randomly pick a part of my image and plot it at the given coords taken from the vector2-list. However, it puts the same image at all coords and keeps randomly replacing them, not with random images but with the same. So the whole board keeps flickering the same icons. Ie, instead of generating 15231 and keeping it frozen, it one second puts 11111 and the next second it puts 33333.
Does anybody understand what im trying to describe ? I'm almost at the point of pulling my own hair out. The cat's hair has already been pulled...
Thx in advance
The Draw function is called once each frame. This line:
int x = slump.Next(2);
Is generating a random number (either a 0 or a 1 in this case) each frame, hence the flicker.
The line after that selects a sprite from your sprite atlas based on that number (specifically it specifies the rectangle containing that sprite). And in the loop that follows you're drawing multiple copies of that sprite (always the same image).
You should be doing all of your game logic in your Update function. That function will give you a time and you will probably want to implement a method of waiting for a certain amount of time to pass before you generate a random block (so keep accumulating the time that passes between each Update, until it reaches some threshold). The exact mechanics of when you want to generate your random block is up to you.
Of course, that is not to mention that there are other flaws in the structure of your code. Bejewelled is played on a fixed-sized board with different coloured blocks (each block you could represent with a number from 1 to X). The location of the blocks should be be implicit in your data structure (so you don't need to generate your platser list).
So your Game class should have something like:
const int BoardWidth = 10;
const int BoardHeight = 10;
int[,] board = new int[BoardWidth, BoardHeight];
Then in your Initialize function you should fill board and perhaps use 0 as an empty space and 1 to X to represent your colours, like so:
for(int x = 0; x < BoardWidth; x++) for(int y = 0; y < BoardHeight; y++)
{
board[x,y] = slump.Next(1, 6); // gives 5 different sprites
}
Then in Update wait for user input or a time-out before modifying the board (depending on your gameplay).
Then in your Draw function do something like this:
for(int x = 0; x < BoardWidth; x++) for(int y = 0; y < BoardHeight; y++)
{
if(board[x,y] == 0) continue; // don't render an empty space
Vector2 position = new Vector2(100*x, 100*y);
Rectangle bildsourcen = new Rectangle(100*(board[x,y]-1), 0, 100, 100);
sb.Draw(allImage, position, bildsourcen, Color.White);
}

Resources