I am trying to resize the following GIF
Original Dimensions are: 1270 x 1270 and a total of 149 Pages
I am resizing to the following Dimensions:
250 x 250 (Successful)
500 x 500 (Successful)
750 x 750 (Unsuccessful)
It fails for the last case and after some digging I found that the limits are set in libvips. I am not able to conclude how the dimensions are violating the constraints.
Constraints Being:
if( (guint64) frame_rect.width * frame_rect.height > INT_MAX / 4 ||
frame_rect.width > 65535 ||
frame_rect.height > 65535 ) {
vips_error( class->nickname, "%s", _( "frame too large" ) );
return( -1 );
}
Currently I have the latest govips(v2.11.0) and vips(8.13.3) versions installed.
I tried different sizes and it is working till 740 x 740. I tried to change the Export Params but am unable to figure the math behind why the frame is too large.
Related
This is from a sample program for OpenCL programming.
I am confused about how global and local work size are computed.
They are computed based on the image size.
Image size is 1920 x 1080 (w x h).
What I assumed is global_work_size[0] and global_work_size[1] are grids on image.
But now global_work_size is {128, 1088}.
Then local_work_size[0] and local_work_size[1] are grids on global_work_size.
local_work_size is {128, 32}.
But total groups, num_groups = 34, it is not 128 x 1088.
Max workgroup_size available at device is 4096.
How is the image distributed into such global and local work group sizes?
They are calculated in the following function.
clGetKernelWorkGroupInfo(histogram_rgba_unorm8, device, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroup_size, NULL);
{
size_t gsize[2];
int w;
if (workgroup_size <= 256)
{
gsize[0] = 16;//workgroup_size is formed into row & col
gsize[1] = workgroup_size / 16;
}
else if (workgroup_size <= 1024)
{
gsize[0] = workgroup_size / 16;
gsize[1] = 16;
}
else
{
gsize[0] = workgroup_size / 32;
gsize[1] = 32;
}
local_work_size[0] = gsize[0];
local_work_size[1] = gsize[1];
w = (image_width + num_pixels_per_work_item - 1) / num_pixels_per_work_item;//to include all pixels, num_pixels_per_work_item is added first
global_work_size[0] = ((w + gsize[0] - 1) / gsize[0]);//col
global_work_size[1] = ((image_height + gsize[1] - 1) / gsize[1]);//row
num_groups = global_work_size[0] * global_work_size[1];
global_work_size[0] *= gsize[0];
global_work_size[1] *= gsize[1];
}
err = clEnqueueNDRangeKernel(queue, histogram_rgba_unorm8, 2, NULL, global_work_size, local_work_size, 0, NULL, NULL);
if (err)
{
printf("clEnqueueNDRangeKernel() failed for histogram_rgba_unorm8 kernel. (%d)\n", err);
return EXIT_FAILURE;
}
I don't see any great mystery here. If you follow the calculation, the values do indeed end up as you say. (Not that the group size is particularly efficient in my opinion.)
If workgroup_size is indeed 4096, gsize will end up as { 128, 32 } as it follows the else logic. (>1024)
w is the number of num_pixels_per_work_item = 32 wide columns, or the minimum number of work-items to cover the entire width, which for an image width of 1920 is 60. In other words, we require an absolute minimum of 60 x 1080 work-items to cover the entire image.
Next, the number of group columns and rows is calculated and temporarily stored in global_work_size. As group width has been set to 128, a w of 60 means we end up with 1 column of groups. (This seems a waste of resources, more than half of the 128 work-items in each group will not be doing anything.) The number of group rows is simply image_height divided by gsize[1] (32) and rounding up. (33.75 -> 34)
Total number of groups can now be determined by multiplying out the grid: num_groups = global_work_size[0] * global_work_size[1]
To get the true total number of work-items in each dimension, each dimension of global_work_size is now multiplied by the group size in this dimension. 1, 34 multiplied by 128, 32 yields 128, 1088.
This actually covers an area of 4096 x 1088 pixels so about 53% of that is wastage. This is mainly because the algorithm for group dimensions favours wide groups, and each work-item works on a 32x1 pixel slice of the image. It would be better to favour tall work groups to reduce the amount of rounding.
For example, if we reverse gsize[0] and gsize[1], in this case we'd get a group size of { 32, 128 }, giving us a global work size of { 64, 1152 } and only 12% wastage. It would also be worth checking if always picking the largest possible group size is even a good idea; it quite possibly isn't, but I've not looked into the kernel's computation in detail, let alone run any measurements, to say if that's the case or not.
I expect this to have more to do with color spaces and their attributes. I was attempting to convert a YUYV to a grayscale image. I used the following function call:
cv::cvtColor(imgOrig, imgGray, cv::COLOR_YUV2GRAY_420);
With this function, I lost some of the height of the image. I could obviously use the resize method to make the original image large enough such that the conversion wouldn't cut out any actual data, but wanted to find out the more appropriate way to go about it.
Looking at the opencv source, below is an excerpt from the cvtColor method:
case COLOR_YUV2GRAY_420:
{
if (dcn <= 0) dcn = 1;
CV_Assert( dcn == 1 );
CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0 && depth == CV_8U );
Size dstSz(sz.width, sz.height * 2 / 3);
_dst.create(dstSz, CV_MAKETYPE(depth, dcn));
dst = _dst.getMat();
#ifdef HAVE_IPP
#if IPP_VERSION_X100 >= 201700
if (CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C1R_L, src.data, (IppSizeL)src.step, dst.data, (IppSizeL)dst.step,
ippiSizeL(dstSz.width, dstSz.height)) >= 0)
break;
#endif
#endif
src(Range(0, dstSz.height), Range::all()).copyTo(dst);
}
break;
You see that on the 8th line, the size of the destination image is made to be two-thirds the size of the source image.
Why is this so? What is the appropriate way to do a color space conversion?
Plainly, it is how YUV420 works. From wikipedia, YUV uses 6 bytes to store 4 pixels. Those 4 pixels share U, V values while having their own Y values. The picture and the formula presented in the conversion from YUV420 to RGB888 section explains it better. They also explain very well why the check
CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0 && depth == CV_8U );
and why the RGB's is only 2/3 of the YUV's.
According to Apple, both CGDisplayModeGetWidth() and CGDisplayModeGetHeight() should return points instead of pixels starting in macOS 10.8. But Apple's word on those APIs isn't consistent because here they say that the functions return pixels and not points.
This confusion is also reflected in practice because both functions only seem to return points sometimes, not all the time. Sometimes they also return pixels. Consider this example:
CGDirectDisplayID id = CGMainDisplayID();
CFArrayRef modes = CGDisplayCopyAllDisplayModes(id, NULL);
CGDisplayModeRef mode;
int c = 0, k, n;
n = CFArrayGetCount(modes);
for(k = 0; k < n; k++) {
mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, k);
printf("GOT SIZE: %d %d\n", (int) CGDisplayModeGetWidth(mode), (int) CGDisplayModeGetHeight(mode));
}
CFRelease(modes);
The code iterates over all available screen modes. In this example, the output is in pixels.
When using this code, however, the output is in points:
CGDirectDisplayID id = CGMainDisplayID();
mode = CGDisplayCopyDisplayMode(id);
printf("NEW GOT SIZE: %d %d\n", (int) CGDisplayModeGetWidth(mode), (int) CGDisplayModeGetHeight(mode));
CGDisplayModeRelease(mode);
But why? Why do CGDisplayModeGetWidth() and CGDisplayModeGetHeight() return pixels in the first code snippet and points in the second? This is confusing me.
To make things even more complicated, starting with macOS 10.8 there are two new APIs, namely CGDisplayModeGetPixelWidth() and CGDisplayModeGetPixelHeight(). These always return pixels, but I still don't understand why CGDisplayModeGetWidth() and CGDisplayModeGetHeight() return pixels in the first code snippet above... is this a bug?
EDIT
Here is the output for my 1680x1050 monitor. I am using Quartz Debug to put the monitor in 840x525 screen mode to do Retina tests. You can see that the output of the first code snippet must be in pixels because it returns modes such as 1680x1050 which would correspond to 3360x2100 pixels if it were points. Another proof that the first code snippet returns pixels not points lies in the fact that the screen mode the monitor is currently in (i.e. 840x525) isn't returned at all. Only the second code snippet returns this mode.
GOT SIZE: 1680 1050
GOT SIZE: 1152 870
GOT SIZE: 1280 1024
GOT SIZE: 1024 768
GOT SIZE: 1024 768
GOT SIZE: 1024 768
GOT SIZE: 832 624
GOT SIZE: 800 600
GOT SIZE: 800 600
GOT SIZE: 800 600
GOT SIZE: 800 600
GOT SIZE: 640 480
GOT SIZE: 640 480
GOT SIZE: 640 480
GOT SIZE: 640 480
GOT SIZE: 1280 1024
GOT SIZE: 1280 960
GOT SIZE: 848 480
GOT SIZE: 1280 960
GOT SIZE: 1360 768
GOT SIZE: 800 500
GOT SIZE: 1024 640
GOT SIZE: 1280 800
GOT SIZE: 1344 1008
GOT SIZE: 1344 840
GOT SIZE: 1600 1000
--------------------------
NEW GOT SIZE: 840 525
I would like to Import a RAW10 file into Matlab. The infos are directly attachted to the jpeg file provided by the raspberry pi camera.
4 Pixels are saved as 5 bytes.
The first four bytes contain the bit 9-2 of a pixel.
The last byte contains the missing LSB.
sizeRAW = 6404096;
sizeHeader =32768;
I = ones(1944,2592);
fin=fopen('0.jpeg','r');
off1 = dir('0.jpeg');
offset = off1.bytes - sizeRAW + sizeHeader;
fseek(fin, offset,'bof');
pixel = ones(1944,2592);
I=fread(fin,1944,'ubit10','l');
for col=1:2592
I(:,col)=fread(fin,1944,'ubit8','l');
col = col+4;
end
fclose(fin);
This is as far as I came yet, but it's not right.
i have an image with size 1162 x 16 which i want to rotate on the touch "moved phase" event ,
the problem is that when the image rotates it gets scrambled "pixelated", although it is not getting scaled ,
i tried with an image of size 128 x 128 but the image was not pixelated,
could it be due to the large size of the image !!
does the rotation affect the image structure???
anyone has an idea why that happens???
or if anyone has a workaround ,, would you please help me with that .
here is the updated code after making it square :
local bck = display.newRect (0,0,display.contentWidth,display.contentHeight)
bck.x = display.contentWidth * 0.5
bck.y = display.contentHeight * 0.5
bck:setFillColor (255,255,255)
local img = display.newImageRect ("laser1.png",1170,1170)
img.x = display.contentWidth * 0.5
img.y = display.contentHeight * 0.5
local function getRotation(PointX1,PointY1,PointX2,PointY2)
--display.getCurrentStage():setFocus ( Bug )
local atan2 = math.atan2
local pi = 3.14159265358
local deltax = PointX2 - PointX1
local deltay = PointY2 - PointY1
local currentAngle = ((atan2(deltay,deltax) )* 180.0) / pi
local rotationDigree = currentAngle - img.previousAngle;
img.previousAngle = currentAngle
return rotationDigree;
end
local function handleTouch ( event )
img.previousAngle = 1
if( event.phase == "moved" ) then
img.rotation = getRotation ( img.x , img.y , event.x , event.y )
end
end
Runtime:addEventListener ("touch",handleTouch)
Your image is not square. This means that when you rotate by 90 degrees (say) you are trying to fit a 16 x 1162 image into a space that's 1162 x 16.
This means that the image is being squashed in one dimension and stretched in the other.
You need to make both the source and target images 1162 x 1162 adding a border, either transparent or some known colour not in the original image so you can remove it once the rotation is complete.
The test image of 128 x 128 works because it's square.