imageData print wrong value - pixel

I need to manipulate pixels in an image and save integer values (0-255) in RGBA values.
let imageData = this.context.getImageData(0, 0, this.width, this.height);
imageData.data[1448] = 10;
imageData.data[1449] = 20;
imageData.data[1450] = 30;
imageData.data[1451] = 40;
this.context.putImageData(imageData, 0, 0);
After get ImageData again and print values in their respective indexes, this is the result:
IDX 1448: 13
IDX 1449: 19,
IDX 1450: 32
IDX 1451: 40
Because the value assigned is not the same as the rescued value???
Thanks!

When you change the alpha of an RGBA pixel, the browser will update the values of the other colors (RGB). For example, if used alpha = 0, the RGB values also be 0.
To resolve this problem, assign the value of 255 to alpha, so it does not impact the other values.

Related

Very unexpected behavior of C++ win32 BitBlt

I noticed when I try to run BitBlt, the resulting data buffer is unexpected in two ways:
It is flipped along the y axis (the origin seems to be bottom left instead of top left)
In each RGBA grouping, the R and B values seem to be switched.
For the first issue, I noticed it when testing with my command prompt; if my command prompt was in the upper left portion of the screen, it would only say it was black when my cursor was in the lower left portion. I had to fix the inversion of the y axis by changing int offset = (y * monitor_width + x) * 4; to int offset = ((monitor_height - 1 - y) * monitor_width + x) * 4; this fixed the pixel location issue because it was showing black where I expected black.
However, the colors were still strong. I tested by trying to get the color of known pixels. I noticed every blue pixel had a very high R value and every red pixel had a very high blue value. That's when I compared with an existing tool I had and found out that the red and blue values seem to be switched in every pixel. At first I thought it was backwards or a byte alignment issue, but I also verified in a clustering of pixels that aren't uniform to make sure it's picking the right position of pixel, and it did perfectly well, just with the colors switched.
Full simplified code below (originally my tool was getting my cursor position and printing the pixel color via hotkey press; this is a simplified version that gets one specific point).
BYTE* my_pixel_data;
HDC hScreenDC = GetDC(GetDesktopWindow());
int BitsPerPixel = GetDeviceCaps(hScreenDC, BITSPIXEL);
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
int monitor_width = GetSystemMetrics(SM_CXSCREEN);
int monitor_height = GetSystemMetrics(SM_CYSCREEN);
std::cout << std::format("monitor width height: {}, {}\n", monitor_width, monitor_height);
BITMAPINFO info;
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biWidth = monitor_width; // client_width;
info.bmiHeader.biHeight = monitor_height; // client_height;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = BitsPerPixel;
info.bmiHeader.biCompression = BI_RGB;
HBITMAP hbitmap = CreateDIBSection(hMemoryDC, &info, DIB_RGB_COLORS, (void**)&my_pixel_data, 0, 0);
SelectObject(hMemoryDC, hbitmap);
BitBlt(hMemoryDC, 0, 0, monitor_width, monitor_height, hScreenDC, 0, 0, SRCCOPY);
int x = 12, y = 12;
int offset = ((monitor_height - 1 - y) * monitor_width + x) * 4;
std::cout << std::format("debug: ({}, {}): ({}, {}, {})\n", x, y, (int)my_pixel_data[offset], (int)my_pixel_data[offset + 1], (int)my_pixel_data[offset + 2], (int)my_pixel_data[offset + 3]);
system("pause");
The output of this will be debug: (12, 12): (199, 76, 133) even though another program has verified the colors are actually (133, 76, 199).
I can easily fix this in my code by flipping the y axis and switching each R and B value and the program will work perfectly well. However, I am just baffled by how this happened and whether there's a more elegant fix.
I can answer the RGB (and it looks like Hans answered the inverted Y axis in a comment). Remember that RGB is stored 0xAARRGGBB, so in that 32 bit value BB is byte 0, GG is byte 1, and RR is byte 2 (alpha is byte 3 if you use it), so when you index in at +0, +1 and +2 you're actually getting the values correctly. When we say RGB we're saying the colors in opposite order of how they're stored in memory.

Increasing count of colors instead of 8

I have completed a programming that can count up to 8 colors in images by using the RGB method from 000 up to 111. I need to do some modification to it. So far I declare the number if above 128 will equal to 1 & below 128 will be 0. It will count the 8 colours. How to increase the number of colours count if let say I do it partially from 0-64,65-128,129-192,193-255.
count=zeros(1,8);
for i = 1:w
for j = 1:h
if redChannel(i,j) > 128,
aredChannel2 = 1;
else
aredChannel2=0;
end
quantizedImage(i,j,1)=aredChannel2*255;
if greenChannel(i,j) > 128,
agreenChannel2 = 1;
else
agreenChannel2=0;
end
quantizedImage(i,j,2)=agreenChannel2*255;
if blueChannel(i,j) > 128,
ablueChannel2 = 1;
else
ablueChannel2=0;
end
quantizedImage(i,j,3)=ablueChannel2*255;
bin=4*aredChannel2+2*agreenChannel2+ablueChannel2+1;
count(bin)=count(bin)+1;
end
end
figure, imshow(uint8(quantizedImage))
Increasing the number of intervals increases the base you are counting in: instead of 2^3=8 quantized colors you will have 4^3=64 quantized colors.
rgb = imread( ... ); %// read you image here
qImage = zeros( size(rgb(:,:,1)) ); %// preallocate result
intervals = permute([64, 128, 192, 256], [1 3 2]); %// the quantization intervals
base = numel(intervals);
for ci=1:size(rgb,3) %// for each channel
whichInterval = bsxfun( #le, rgb(:,:,ci), intervals ); %// select per pixel, which interval is relevant
[~, q] = max( whichInterval, [], 3 ); %// get index of relevant interval
qImage = qImage*base + (q-1); %// -1 to convert from matlab's 1-based indexing
end

find the white/ black pixels in specific region javacv

I have tried this code. 540 is the left most x value of the box,3 is left most y value of the box,262 - width ,23 -height of the region which I am going to calculate the ratio of the white/black pixels. What I really wanted to do is detect the number of white/black pixel ratio in a specific region.I have calculate the coordinates for each cell (regions which I am going to specified)and try with this code.But the error in counting.
Can I please have an idea about this issue please..
I am really stuck here with my final year project.
CvSize cvSize = cvSize(img.width(), img.height());
IplImage image = cvCreateImage(cvSize, IPL_DEPTH_8U, 1);
IplImage image2 = cvCreateImage(cvSize, IPL_DEPTH_8U, 3);
cvCvtColor(image2, image, CV_RGB2GRAY);
cvSetImageROI(image2, cvRect(540,3,262,23));
//IplImage image2 = cvCreateImage(cvSize, IPL_DEPTH_8U, 3);
//
//cvCvtColor(arg0, arg1, arg2)
// cvCvtColor(image2, image, CV_RGB2GRAY);
//cvThreshold(image, image, 128, 255, CV_THRESH_BINARY);
CvLineIterator iterator = new CvLineIterator();
double sum = 0, green_sum = 0, red_sum = 0;
CvPoint p2 = new CvPoint(802,3);
CvPoint p1 = new CvPoint(540,26);
int lineCount = cvInitLineIterator(image2, p1, p2, iterator, 8, 0 );
for (int i = 0; i < lineCount; i++) {
sum += iterator.ptr().get() & 0xFF;
}
System.out.println("sum................"+sum);
CV_NEXT_LINE_POINT(iterator);
}
}
it gave the result as sum................0.0
I have really stuck with this..can you please give any solution for this issue please
Move CV_NEXT_LINE_POINT(iterator); line inside the for loop. Then it should work.

Count the number of black pixels using ByteBuffer javacv

I have use this code..I am new to javacv and I need to get the pixels one by one in a region and get the color of that pixel. Can I please know how to do it using the ByteBuffer ,because byte buffer can read pixel by pixel and I need to check whether the pixel is black or white...
Can anyone please consider about this..I am really stuck here...
IplImage img=cvLoadImage("img\\ROI.jpg");
CvScalar Black = cvScalar(0, 0, 0, 0);
CvScalar white = cvScalar(255, 255, 255, 255);
ByteBuffer buffer = img.getByteBuffer();
for(int y = 0; y < img.height(); y++) {
for(int x = 0; x < img.width(); x++) {
int index = y * img.widthStep() + x * img.nChannels();
// Used to read the pixel value - the 0xFF is needed to cast from
// an unsigned byte to an int.
int value = buffer.get(index) & 0xFF;
// Sets the pixel to a value (greyscale).
buffer.put(index, (byte) value);
// Sets the pixel to a value (RGB, stored in BGR order).
//buffer.putInt(index, Black);
// buffer.put(index + 1, white);
}
}

How to randomly fill a space in one dimension?

I would like to know how can I randomly fill a space with a set number of items and a target size, for example given the number of columns = 15 and a target size width = 320, how can I randomly distribute the columns width to fill the space? like shown in the image below if possible any sort of pseudo-code or algorithm will do
One way to partition your 320 pixels in 15 random "columns" is to do it uniformly, i.e., every column width follows the same distribution.
For this, your actually need a uniform distribution on the simplex. The first way to achieve is the one described by yi_H, and is probably the way to go:
Generate 14 uniform integers between 0 and 320.
Keep regenerating any number that has already been chosen, so that you end up with 14 distinct numbers
Sort them
Your columns bounds are given by two consecutive random numbers.
If you have a minimum width requirement (e.g., 1 for non-empty columns), remove it 15 times from your 320 pixels, generate the numbers in the new range and make the necessary adjustments.
The second way to achieve a uniform point on a simplex is a bit more involved, and not very well suited with discrete settings such as pixels, but here it is in brief anyway:
Generate 15 exponential random variables with same shape parameter (e.g. 1)
Divide each number by the total, so that each is in [0,1]
Rescale those number by multiplying them by 320, and round them. These are your column widths
This is not as nice as the first way, since with the rounding you may end with a total bigger or smaller than 320, and you may have columns with 0 width... The only advantage is that you don't need to perform any sort (but you have to compute logarithms... so all in all, the first way is the way to go).
I should add that if you do not necessarily want uniform random filling, then you have a lot more algorithms at your disposal.
Edit: Here is a quick implementation of the first algorithm in Mathematica. Note that in order to avoid generating points until they are all different, you can just consider that an empty column has a width of 1, and then a minimum width of 2 will give you columns with non-empty interior:
min = 2;
total = 320;
height = 50;
n = 15;
x = Sort[RandomInteger[total - n*min - 1, n - 1]] + Range[n - 1]*min
Graphics[{Rectangle[{-2, 0}, {0, height}], (*left margin*)
Rectangle[{#, 0}, {# + 1, height}] & /# x, (*columns borders*)
Rectangle[{total, 0}, {total + 2, height}]}, (*right margin*)
PlotRange -> {{-2, total + 2}, {0, height}},
ImageSize -> {total + 4, height}]
with gives the following example output:
Edit: Here is the modified javascript algorithm (beware, I have never written Javascript before, so there might be some errors\poor style):
function sortNumber(a,b)
{
return a - b;
}
function draw() {
var canvas = document.getElementById( "myCanvas" );
var numberOfStrips = 15;
var initPosX = 10;
var initPosY = 10;
var width = 320;
var height = 240;
var minColWidth = 2;
var reducedWidth = width - numberOfStrips * minColWidth;
var separators = new Array();
for ( var n = 0; n < numberOfStrips - 1; n++ ) {
separators[n] = Math.floor(Math.random() * reducedWidth);
}
separators.sort(sortNumber);
for ( var n = 0; n < numberOfStrips - 1; n++ ) {
separators[n] += (n+1) * minColWidth;
}
if ( canvas.getContext ) {
var ctx = canvas.getContext( "2d" );
// Draw lines
ctx.lineWidth = 1;
ctx.strokeStyle = "rgb( 120, 120, 120 )";
for ( var n = 0; n < numberOfStrips - 1; n++ ) {
var newPosX = separators[n];
ctx.moveTo( initPosX + newPosX, initPosY );
ctx.lineTo( initPosX + newPosX, initPosY + height );
}
ctx.stroke();
// Draw enclosing rectangle
ctx.lineWidth = 4;
ctx.strokeStyle = "rgb( 0, 0, 0 )";
ctx.strokeRect( initPosX, initPosY, width, height );
}
}
Additionally, note that minColWidth should not be bigger than a certain value (reducedWidth should not be negative...), but it is not tested in the algorithm. As stated before, us a value of 0 if you don't mind two lines on one another, a value of 1 if you don't mind two lines next to each other, and a value of 2 or more if you want non-empty columns only.
Create 14 unique numbers in the range (0,320). Those will be the x position of the bars.
Create random number, compare with previous ones, store it.
If consecutive lines aren't allowed, also check that it doesn't equal with any previous+-1.

Resources