Bitmap scaling while keeping centered - c

I'm developing an image viewer on embedded system(stm32f4) with multi-touch support. To put into perspective image viewer should have similar functionality like something you find on your smartphone.
I have completed the image scaling and pinch/zoom gesture recognition part. But it only scales from the source image origin coordinates. So if my origin(x,y[0, 0]) is top left then it will scale following that point. And if I want to look something up in bottom right corner I have to use pinch gesture and the move to location I want which is undesirable.Here's how it looks
http://i.imgur.com/IWR4wls.gifv
. It should follow center of 2 fingers.
How can I achieve scaling while following center of 2 fingers? My attempts to do it resulted in working but jumpy, shaky version basically unusable.
My scaling works by having source image always opened(in ram) taking source image [x,y] coordinates and rect i want to zoom [w,h] scaling that rect to display [w,h] and displaying it. Moving(pan gesture) is done by moving zoomRect [x,y] coordinates in source image. That means every time I move finger I have to move zoomedRect (increase [x,y]) scale that zoomedRect and display it. So fully scaled image is not being stored because of limited ram.
Source image width,height[640, 480]:
+-------------------------------+
| zoomedRect |
| +--------------+ |
| | | |
| | | |
| | | |
| | | |
| | | |
| +--------------+ |
| |
| |
| |
+-------------------------------+
I take zoomedRect i.e. x,y[50, 50] width,height[160, 120]
and scale it to display size w,h[640x480]
Display:
+-------------------------------+
| |
| |
| |
| |
| |
| |
| |
| |
| |
+-------------------------------+
Here's what I have/can calculate:
Center of 2 fingers.
Translate center of 2 fingers to source image(even when zoomed in).
Scale in fraction(1.32, 1.45...) and (source image width|height)/(zoomedRect width|height).
Edit:
I have tried to calculate center point when 2 fingers touched and then use that center for future calculations and that's the reason why all the jumping and shaking happen. But maybe there is an error on my side so I'll add some relevant code.
As I mentioned earlier I change zoomRect width, height to scale image
newWidth = tempWidth / scale;
newHeight = tempHeight / scale;
So after zooming I need to also move near center and I do that by calculating how much scale changed
(lastWidth - newWidth)
newSourceX = newSourceX + ((int16_t)lastWidth - newWidth);
newSourceY = newSourceY + ((int16_t)lastHeight - newHeight);
Now we need to stop at calculated center between the 2 fingers and not get out of bounds [0, 0]:
#define LIMIT(value, min, max) (value < min ? min : (value > max ? max : value))
newSourceX = LIMIT(newSourceX + ((int16_t)lastWidth - newWidth), 0, centerSourceX);
newSourceY = LIMIT(newSourceY + ((int16_t)lastHeight - newHeight), 0, centerSourceY);
So far so good but it is not properly centered
Calculate center between two fingers on Display and translate to Source.
Because it's fully zoomed out(Source and Display are identical)
centers are also in identical positions.
Display/Source:
+-------------------------------+
| |
| |
| |
| |
| |
| centerPos |
| * |
| |
| |
+-------------------------------+
So if we zoom in zoomRect will be newWidth / 2 and newHeight / 2 further than needed.
Source:
+-------------------------------+
| |
| |
| |
| |
| |
| centerPos |
| *---------+
| | zoomRect|
| | |
+---------------------+---------+
To account for this I modify code as follows:
newSourceX = LIMIT(newSourceX + ((int16_t)lastWidth - newWidth), 0, centerSourceX - newWidth / 2);
newSourceY = LIMIT(newSourceY + ((int16_t)lastHeight - newHeight), 0, centerSourceY - newHeight / 2);
Success!!! Or not?
Source:
+-------------------------------+
| |
| |
| |
| zoomRect |
| +---------+ |
| |centerPos| |
| | * | |
| +---------+ |
| |
+-------------------------------+
When zooming from 1:1 it works perfectly but when I want to zoom again when
I'm zoomed in a little bit the "jump" happens because:
newSourceX + ((int16_t)lastWidth - newWidth) > centerSourceX - newWidth / 2
Result: http://i.imgur.com/x1t6X2q.gifv

You have source picture, and source coordinates (x,y) are transformed in screen coordinates with affine transformation. I assume that scaling is uniform. At the beginning Scale=1; dx, dy=0
ScrX = (x - dx) * Scale
ScrY = (y - dy) * Scale
So we see piece of source image that was cut from dx,dy point and extended by Scale times.
Example for dx=1,dy=1, Scale=2. Left rect is source, right one is screen.
Let we begin (b prefix) zooming in screen positions of fingers (bx0, by0) and (bx1, by1) - opposite rectangle corners. And end (or intermediate) positions (e prefix)are (ex0, ey0) and (ex1, ey1)
Let diagonals of rectangle correspond to scale degree:
eScale = bScale * Sqrt(((ex1-ex0)^2 + (ey1-ey0)^2) / ((bx1-bx0)^2 + (by1-by0)^2))
//use Math.Hypot or Vector.Length if available
So we have got new scale.
And we have beginning and ending central points
bcx = (bx0 + bx1) / 2
bcy = (by0 + by1) / 2
ecx = (ex0 + ex1) / 2
ecy = (ey0 + ey1) / 2
Both these screen points should correspond to the same source coordinate
bcx = (xx - bdx) * bScale
ecx = (xx - edx) * eScale
excluding xx we get
edx = bdx + bcx / bScale - ecx / eScale
and similar formula for edy
So we have got new shift parameters.

Perhaps lock the centre point of image from the 1st point you can calculate the centre of the two fingers, and then scale from this point. Rather than recompute the centre point each time. Take it as the zoom point and then movement of fingers from this point are the zoom factor, should stop the shaking effect you mentioned

Related

How to combine rows into one column based on boolean values in Google Sheets?

I'm having a hard time wrapping my mind around how to approach this...
Say I have a table with several items with different potential properties, which are assigned a boolean value for each property for each item. (in this case we have several options for each "color" and "size")
| Color | Size
-----------------------------------------------------------------------
Item | Red | Blue | White | Black | Tan | Large | Medium | Small
-----------------------------------------------------------------------
Pants | | y | | y | y | y | y | y |
Shirt | y | | y | y | | y | y | y |
Skirt | | y | y | | | | y | y |
Socks | y | y | y | y | y | y | y | y |
And I want to then output this into a single column like:
Pants, Blue, Large
Pants, Blue, Medium
Pants, Blue, Small
Pants, Black, Large
Pants, Black, Medium
Pants, Black, Small
Pants, Tan, Large
Pants, Tan, Medium
Pants, Tan, Small
Shirt, Red, Large
etc etc
So, I'm trying to populate a column with all the possible results of the true values for each row, concatenated with the header for each column that has a true value. In this example, it would further break out color and size for each item.
Thoughts on the best approach to this in Google Sheets?
Example sheet:
https://docs.google.com/spreadsheets/d/199msbUtUuZzb0HvBMgjQW98hRt3StFEyUFfTfLzSQzw/edit?usp=sharing
on a small scale:
=ARRAYFORMULA(TRANSPOSE(SPLIT(TEXTJOIN("\", 1,
IF(B3:F6="y", REPT(A3:A6&", "&B2:F2&"\", MMULT(N(G3:I6="y"),
TRANSPOSE(COLUMN(G2:I2)^0))), )), "\"))&", "&
TRANSPOSE(SPLIT(JOIN(" ", REPT(TRIM(TRANSPOSE(QUERY(TRANSPOSE(
IF(G3:I6="y", G2:I2, )),, COLUMNS(IF(G3:I6="y", G2:I2, )))))&" ",
MMULT(N(B3:F6="y"), TRANSPOSE(COLUMN(B3:F6)^0)))), " ")))
for just combo of two:
=ARRAYFORMULA(QUERY(TRANSPOSE(SPLIT(QUERY(TRANSPOSE(QUERY(
IF(B3:F="y", "♦"&A3:A&", "&B2:F2&"♦", ),,99^99)),,99^99), "♦")),
"where not Col1 starts with ' ' order by Col1"))
modded #MK formula to mimic CSV:
=ARRAYFORMULA(TRANSPOSE(QUERY(TRANSPOSE(QUERY(VLOOKUP(SEQUENCE(4*5*3, 1, 0)/(5*3)+3,
{ROW(A:A), A:A&",", IF(B:I="y", {B2:F2&",", G2:I2}, )},
INT(MOD(SEQUENCE(4*5*3, 1, 0), {9^99, 5*3, 3})/{9^99, 4, 1})+{2, 3, 3+4}),
"where Col2<>'' and Col3<>''")),,9^99)))
For problems like these, I like to use a VLOOKUP() with an [index] value that is made up of an array constructed out of some of the parameters of your data. I made a new tab called mK.Help and put this formula there which will retabulate your data into the way you're hoping (i think).
If you definitely want comma separated, I can help with that, but usually folks just want the data in columns. each of the parameters is fed by a simple formula counting the various aspects of your data. The big reorganizing formula can be rewritten to include each of those formulae instead of referring to a helper cell, but I have found that it is easier for folks to understand what's going on when I leave it broken out like that.
=ARRAYFORMULA(QUERY(VLOOKUP(SEQUENCE(Q3*Q4*Q5,1,0)/(Q4*Q5)+Q2,{ROW(A:A),A:A,IF(B:I="y",B2:I2,)},INT(MOD(SEQUENCE(Q3*Q4*Q5,1,0),{9^99,Q4*Q5,Q5})/{9^99,Q5,1})+{2,3,3+Q4}),"where Col2<>'' and Col3<>''"))

XGetImage takes a lot of time to run

XGetImage takes 3-4 seconds to execute and completely freezes X11
Display *display;
display = XOpenDisplay(NULL);
if (!display) {fprintf(stderr, "unable to connect to display");return 7;}
Window w;
int x,y,i;
unsigned m;
Window root = XDefaultRootWindow(display);
if (!root) {fprintf(stderr, "unable to open rootwindow");return 8;}
//sleep(1);
if(!XQueryPointer(display,root,&root,&w,&x,&y,&i,&i,&m))
{ printf("unable to query pointer\n"); return 9;}
XImage *image;
XWindowAttributes attr;
XGetWindowAttributes(display, root, &attr);
image = XGetImage(display,root,0,0,attr.width,attr.height,AllPlanes,XYPixmap);
XCloseDisplay(display);
if (!image) {printf("unable to get image\n"); return 10;}
In the Xorg log:
[ 13234.693] AUDIT: Thu Jan 7 20:12:13 2016: 3856: client 45 connected from local host ( uid=500 gid=500 pid=12993 )
Auth name: MIT-MAGIC-COOKIE-1 ID: 153
[ 13238.774] AUDIT: Thu Jan 7 20:12:18 2016: 3856: client 45 disconnected
time:
real 0m4.080s
user 0m0.002s
sys 0m0.007s
Ideally I want this function to run in less than 0.1 seconds
XYPixmap is a very specialized format that doesn't have many uses. You should use ZPixmap nearly always.
XYPixmap works plane by plane. What does it mean? Take bit 0 of every pixel, and tightly pack all these bits in an array of unsigned int. That's youir plane 0. Then take bit 1 of every pixel, and pack all these bits in an array. That's your plane 1. Then take bit 2 of every pixel...
Framebuffer
__________________________________________________________________
/
Pixel 0 Pixel 1 Pixel 2
[0][1][2][3][4][5][6][7] [0][1][2][3][4][5][6][7] [0][1][2]....
| | |
| +------------------------+ |
| | |
| | +--------------------------------------------------+
| | |
v v v
[0][0][0]..... \
(Plane 0) |
|
[1][1][1].... | Result
(Plane 1) |
.... |
[7][7][7].... |
(Plane 7) |
/
If your framebuffer is stored like this, which is the case for most modern hardware, that's a lot of bit manipulation!
The picture shows 8 bit pixels, but it's the same for any other depth.
ZPixmap on the other hand takes entire pixels and stuffs them into an array:
Framebuffer
__________________________________________________________________
/
Pixel 0 Pixel 1 Pixel 2
[0][1][2][3][4][5][6][7] [0][1][2][3][4][5][6][7] [0][1][2]....
| | | | | | | | | | | | | | | | | | |
v v v v v v v v v v v v v v v v v v v
[0][1][2][3][4][5][6][7] [0][1][2][3][4][5][6][7] [0][1][2]....
\_____________________________________________________________________
Result
This is simple direct copying, which should be very fast.

Set real transparency of a label

I'm coding a winform application in c++/cli.
In this app I have a graph on a pictureBox and, to point some interesting data, I'm using a marker coded as a label. To achieve transparency, I have set:
label1->Parent = picbureBox1;
and set the BackColor to Transparent but I noticed it is a real transparency because it is not transparent to lines drew on the pictureBox but only to the background. This is what happens:
/ 1 | / 2
/ --------- |
/ |label1 | | |label1|
/ --------- |
/ | /
Even if it is transparent, my label covers the line when the label moves from 1 to 2.
What I would like to achieve is this:
/ 1 | / 2
/ --------- | /
/ |label1 | | |label1|
/ --------- | /
/ | /
Is this possible or should I redraw the line when the marker covers it?

how to make gluLookAt and glPerspective to work like glortho?

I don't know how to setup distance
where I should stand to look at my 2d stuff(which at center there is a ball pos:1024/2,768/2)
I use gluLookAt and glPerspective to give my 2d rotated object more 3d feel
anyway here is the code I use with glOrtho:
glMatrixMode ( GL_PROJECTION );
glLoadIdentity();
glOrthof ( 0, 1024, 768, 0, 0, 1000.0f );
glMatrixMode ( GL_MODELVIEW );
glLoadIdentity();
and this is when I try to setup with glPerspective and gluLookAt:
glMatrixMode ( GL_PROJECTION );
glLoadIdentity();
gluPerspective(90,1024/768,0,300);
gluLookAt(1024 * 0.5,768 * 0.5f,-????, 1024 * 0.5,768 * 0.5,0, 0,-1,0);
glMatrixMode ( GL_MODELVIEW );
glLoadIdentity();
Basically I just want those codes that works the same,I am not sure how to setup the fovy value of gluPerspective,and the ??? from gluLookAt,how to project the full size with width 1024,and height 768?
Well glOrtho is supposed to yield a parallel projection, so essentially using gluPerspective is going exactly the other way. If you're hoping to find a special case of gluPerspective that acts like glOrtho, the problem is that the matrices they generate are different in some ways you can't reach - note the bottom right corner, in particular, in what they generate:
glOrtho
| 2 |
|---------- 0 0 t |
|right-left x |
| |
| 2 |
| 0 ---------- 0 t |
| top-bottom y |
| |
| |
| 0 0 -2 |
| -------- t |
| far-near z |
| |
| 0 0 0 1 |
gluPerspective
| f |
| ------ 0 0 0 |
| aspect |
| |
| 0 f 0 0 |
| |
| zFar+zNear 2*zFar*zNear |
| 0 0 ---------- ------------ |
| zNear-zFar zNear-zFar |
| |
| 0 0 -1 0 |
So it's going to be hard to set the 2/(top-bottom) and the bottom row correctly, for starters.
If this line is the core of your issue:
gluLookAt(1024 * 0.5,768 * 0.5f,-????, 1024 * 0.5,768 * 0.5,0, 0,-1,0);
...then just set thee -???? to a positive value indicating the distance to your eye from the center of the scene (OpenGL's positive Z points towards the viewer).

How can I draw a concave corner rectangle in WPF?

How can I draw a concave corner rectangle in WPF?
You can create this by Path Operation under Expression blend (Menu - Object-> Path operations) I have created a Path by subtracting four ellipse against a rectangle.
the Path.Data for a concave rectangle is given below, #Kent Fredric logic in the previous answer will be helpful to implement one.
M17.200002,0L120.4,0 120.4,2.3066998E-06C120.4,6.7378696,128.10079,12.200001,137.60001,12.200001L137.60001,85.400003C128.10077,85.400003,120.4,90.862138,120.4,97.6L17.200002,97.6C17.200002,90.862151,9.4993697,85.400003,0,85.400003L0,12.199999C9.4993663,12.200015,17.200002,6.7378725,17.200002,0z
See the blog post here http://jobijoy.blogspot.com/2008/11/concave-cornered-rectangle-blend-tip.html
Another way to get this is to create a WPF Custom Shape like bellow
public class ConcaveRectangle:System.Windows.Shapes.Shape
do you mean a rectangle with concave corners?, ie:
____________________
| |
__| |__
| |
| |
| |
|__ __|
| |
|____________________|
Given a rectangle of dimension w x h with corner radius r
There are 4 corners:
A : 0,0
B : w,0
C : w,h
D : 0,h
There is an implicit minimum size of
w = 2r
h = 2r
There are 4 Circle Centers, A,B,C,D
And there's thus a grid of edge points:
(0,0)--(0+r,0)---(w-r,0)---(w,0)
| |
(0,0+r) (w,0+r)
| |
| |
(0,h-r) (w,h-r)
| |
(0,h)--(0+r,h)---(w-r,h)---(w,h)
Then its merely a case of computing the arc from one point to another.
I should point out that if it's concave, the four sides aren't both identical and straight; thus it's not a rectangle. But I digress.

Resources