Sketchup ruby translate, rotate, scale - ruby

I am developing plugin to load multiple bojects to model and performing multiple transformations
I am working almost one week i go through sketchucation, sketchup ruby documentation, transformation matrices topics etc and i cannot figure what i am doing wrong.
I am 100% sure that scalling and translating works, but i dont know what about rotations, basiaclly i want to rotate given object around axis.
I would really appreciate any kind of professional ruby plugin makers help!!!
My target is to achieve such component:
but my current result is:
My code is here, i know it is not shortest:
#1)Scale
scale_transformation = Geom::Transformation.scaling(#transform.scale_vector[0],
#transform.scale_vector[1],
#transform.scale_vector[2])
#2)Rotate
vector = Geom::Vector3d.new(1, 0, 0)#x axis
rotate_transformation_x = Geom::Transformation.rotation(#transform.transformation.origin, vector, #transform.rotation_vector[0].degrees)#degrees->radians
vector = Geom::Vector3d.new(0, 1, 0)#y axis
rotate_transformation_y = Geom::Transformation.rotation(#transform.transformation.origin, vector, #transform.rotation_vector[1].degrees)#degrees->radians
vector = Geom::Vector3d.new(0, 0, 1)#z axis
rotate_transformation_z = Geom::Transformation.rotation(#transform.transformation.origin, vector, #transform.rotation_vector[2].degrees)#degrees->radians
#if rotate is [0, 0, 0] than rotate transformation is identity matrix:
if(#transform.rotation_vector[0] == 0 )
rotate_transformation_x = Geom::Transformation.new()
end
if(#transform.rotation_vector[1] == 0 )
rotate_transformation_y = Geom::Transformation.new()
end
if(#transform.rotation_vector[2] == 0 )
rotate_transformation_z = Geom::Transformation.new()
end
rotate_transformation = rotate_transformation_x * rotate_transformation_y * rotate_transformation_z
#3)Translate
translate_transformation = Geom::Transformation.translation(Geom::Vector3d.new(
meters_to_inches(#transform.translation_vector[0]),
meters_to_inches(#transform.translation_vector[1]),
meters_to_inches(#transform.translation_vector[2])
))
#if translate is [0, 0, 0] than translate transformation is identity matrix:
if(#transform.translation_vector[0] == 0 && #transform.translation_vector[1] == 0 && #transform.translation_vector[2] == 0 )
translate_transformation = Geom::Transformation.new()
end
#using overloaded operator '*' for matrixes
puts #path + "\r\nFROM PARENT : " + #transform.to_s + ", matrix = " + #transform.transformation.to_a.each_slice(4).inject { |str, row| "#{str}\r\n#{row}" }
#transform.transformation = (translate_transformation * rotate_transformation * scale_transformation) * #transform.transformation
#transform.transformation if there was not previous transformation is identity matrix.
I think my mistake can be connected with order of multiplying matrices
THANK YOU FOR ANY KIND OF HELP!!!
rotation and translation definition are as follows(for example):

Related

2D Image transformations by pixel

I am trying to do a translation, euclidian, similarity, affine and projective transformation on an image pixel by pixel. the input for my program is the image name and the transformation matrix.
This is my code
function imagetrans(name, m)
Image = imread(name);
[rows, cols] = size(Image);
newImage(1:rows,1:cols) = 1;
for row = 1 : rows
for col = 1 : cols
if(Image(row,col) == 0)
point = [row;col;1];
answer = m * point;
answer = int8(answer);
newx = answer(1,1);
newy = answer(2,1);
newImage(newx,newy) = 0;
end
end
end
imshow(newImage);
end
This is the image
Right now I am testing just a translation matrix.
matrix =
1 0 7
0 1 2
0 0 1
when I pass the image and matrix through the function my result is just a little black line
What am I doing wrong?
Using the matlab debugger, I noticed that that you are casting to int8, which is too small too represent all indices. So, you should use int32/int64 or uint32/uint64 instead, i.e.
answer = uint8(answer);
should be
answer = uint32(answer);
Please try to use the Matlab debugger before asking the question: why does it not work?

Morphing vertices' positions between multiple 3d models with three.js

I am trying to transition between 3+ 3D models with some nice perlin noise based on user input, just like this:
http://experience.mausoleodiaugusto.it/en/
http://na.leagueoflegends.com/en/featured/skins/project-2016
I can easily transition between two models in my vertex shader, passing down a u_morphFactor uniform variable, which I tween between 0 and 1 (0 = first model, 1 = second model). My question is how should I do it with 3 or more models.
Here is how I handle my geometry:
class CustomGeometry extends THREE.BufferGeometry {
// pass down the two models' reference geometries
constructor (geo1, geo2) {
super()
let { count } = geo1.attributes.position
let timeArray = new Float32Array(count)
let targetArray = new Float32Array(count)
for (let i = 0; i < count; i += 3) {
// assign next model's vertex position to the current one.
// if there are is no corresponding vertex, simply move to vec3(0, 0, 0)
targetArray[i + 0] = geo2.attributes.position.array[i + 0] || 0
targetArray[i + 1] = geo2.attributes.position.array[i + 1] || 0
targetArray[i + 2] = geo2.attributes.position.array[i + 2] || 0
}
// assign position AND targetPosition as attributes, so we can transition between them
this.addAttribute('a_targetPosition', new THREE.BufferAttribute(targetArray, 3))
this.addAttribute('position', geo1.attributes.position)
}
}
Now with the two models' vertices uploaded to the GPU, I can pass down the uniform and make my transition:
let uniforms = {
u_time: { value: 0 },
u_morphFactor: { value: 0 } // show first model by default
}
And the GLSL is:
vec3 new_position = mix(position, a_targetPosition, u_morphFactor);
However, I still can't wrap my head around how should I approach this same technique with 3 or more models. I guess I have to mess with the shader math that handles u_morphFactor..
TL;DR: I know how to map vertices from one 3D model to the next, simply going from 0 to 1 in my shaders. How do I do this with 3 or more models?

Check for pixel values in a neighborhood

I'm trying to write a MATLAB script that does the following:
Given: pixel coordinates(x,y) for a .jpg image
Goal: Check, within a 5 pixel radius of given coordinates, if there is a pixel of a certain value.
For example, let's say I'm given the coordinates (100,100), then I want to check the neighborhood of (100,100) within my image for any pixels that are black (0,0,0). So perhaps, pixel (103, 100) and (104,100) might have the value (0,0,0).
Current code:
x_coord = uint32(coord(:,1));
y_coord = uint32(coord(:,2));
count = 0;
for i = 1:length(x_coord)
%(img(x,y) returns pixel value at that (x,y)
%Note 0 = black. Indicating that, at that position, the image is just
% black
if img(x_coord(i),y_coord(i)) == 0
count = count + 1;
end
end
It currently only checks at an exact location. Not in a local neighborhood. How to could I extend this?
EDIT: Also note, as long as there as at least one pixel in the neighborhood with the value, I increment count. I'm not trying to enumerate how many pixels in the neighborhood have that value, just trying to find evidence of at least one pixel that has that value.
EDIT:
Even though I am unable to identify an error with the code, I am not able to get the exact results I want. Here is the code I am using.
val = 0; %pixel value to check
N = 50; % neighbourhood radius
%2D grid of coordinates surrounding center coordinate
[R, C] = ndgrid(1 : size(img, 1), 1 : size(img, 2));
for kk = 1 : size(coord, 1)
r = coord(kk, 1); c = coord(kk, 2); % Get pixel locations
% mask of valid locations within the neighbourhood (avoid boundary problems)
mask = (R - r).^2 + (C - c).^2 <= N*N;
pix = img(mask); % Get the valid pixels
valid = any(pix(:) ~= val);
% Add either 0 or 1 depending if we have found any matching pixels
if(valid == 1)
img = insertMarker(img, [r c], 'x', 'color', 'red', 'size', 10);
imwrite(img, images(i).name,'tiff');
end
count = count + valid;
end
An easier way to do this would be to use indexing to grab a neighbourhood, then to check to see if any of the pixels in the neighbourhood have the value that you're looking for, use any on a flattened version of this neighbourhood. The trick with grabbing the right neighbourhood is to first generate a 2D grid of coordinates that span the entire dimensions of your image, then simply use the equation of a circle with the centre of it being each coordinate you are looking at and determine those locations that satisfy the following equation:
(x - a)^2 + (y - b)^2 <= N^2
N is the radius of the observation window, (a, b) is a coordinate of interest while (x, y) is a coordinate in the image. Use meshgrid to generate the coordinates.
You would use the above equation to create a logical mask, index into your image to pull the locations that are valid within the mask and check how many pixels match the one you want. Another added benefit with the above approach is that you are not subject to any out of bounds errors. Because you are pre-generating the list of all valid coordinates in your image, generating the mask will confine you within the boundaries of the image so you never have to check for out of boundaries conditions.... even when you specify coordinates to search that are out of bounds.
Specifically, assuming your image is stored in img, you would do:
count = 0; % Remembers total count of pixels matching a value
val = 0; % Value to match
N = 50; % Radius of neighbourhood
% Generate 2D grid of coordinates
[x, y] = meshgrid(1 : size(img, 2), 1 : size(img, 1));
% For each coordinate to check...
for kk = 1 : size(coord, 1)
a = coord(kk, 1); b = coord(kk, 2); % Get the pixel locations
mask = (x - a).^2 + (y - b).^2 <= N*N; % Get a mask of valid locations
% within the neighbourhood
pix = img(mask); % Get the valid pixels
count = count + any(pix(:) == val); % Add either 0 or 1 depending if
% we have found any matching pixels
end
The proposed solution:
fc = repmat(-5:5,11,1);
I = (fc.^2+fc'.^2)<=25;
fc_x = fc(I);
fc_y = fc'; fc_y = fc_y(I);
for i = 1:length(x_coord)
x_toCheck = fc_x + x_coord(i);
y_toCheck = fc_y + y_coord(i);
I = x_toCheck>0 & x_toCheck<=yourImageWidth;
I = I.*(y_toCheck>0 & y_toCheck<=yourImageHeight);
x_toCheck = x_toCheck(logical(I));
y_toCheck = y_toCheck(logical(I));
count = sum(img(x_toCheck(:),y_toCheck(:)) == 0);
end
If your img function can only check one pixel at a time, just add a for loop:
for i = 1:length(x_coord)
x_toCheck = fc_x + x_coord(i);
y_toCheck = fc_y + y_coord(i);
I = x_toCheck>0 & x_toCheck<=yourImageWidth;
I = I.*(y_toCheck>0 & y_toCheck<=yourImageHeight);
x_toCheck = x_toCheck(logical(I));
y_toCheck = y_toCheck(logical(I));
for j = 1:length(x_toCheck)
count = count + (img(x_toCheck(j),y_toCheck(j)) == 0);
end
end
Step-by-step:
You first need to get all the coordinates within 5 pixels range of the given coordinate.
We start by building a square of 11 pixels in length/width.
fc = repmat(-5:5,11,1);
fc_x = fc;
fc_y = fc';
plot(fc_x,fc_y,'.');
We now need to build a filter to get rid of those points outside the 5-pixel radius.
I = (fc.^2+fc'.^2)<=25;
Apply the filter, so we can get a circle of 5-pixel radius.
fc_x = fc_x(I);
fc_y = fc_y(I);
Next translate the centre of the circle to the given coordinate:
x_toCheck = fc_x + x_coord(i);
y_toCheck = fc_y + y_coord(i);
You need to check whether part of the circle is outside the range of your image:
I = x_toCheck>0 & x_toCheck<=yourImageWidth;
I = I.*(y_toCheck>0 & y_toCheck<=yourImageHeight);
x_toCheck = x_toCheck(logical(I));
y_toCheck = y_toCheck(logical(I));
Finally count the pixels:
count = sum(img(x_toCheck,y_toCheck) == 0);

Determining 2D Affine Transformation of Images

I am having a problem determining the affine transformation matrix of below image.
Original Image:
Affine Transformed Image:
I determined 2 points on the images to solve affine transformation matrix, but the results I get does not convert original to desired.
The code is below, it first solves the matrix and use it to transform original to transformed version:
% Pixel values
p1_aff = [164; 470];
p1_nor = [1; 512];
p2_aff = [470; 164];
p2_nor = [512; 1];
%p3_aff = [131;68];
%p3_nor = [166;61];
%p4_aff = [328;90];
%p4_nor = [456;59];
%Transformation matrix
syms a11 a12 a21 a22;
A = [a11 a12; a21 a22];
%Solving matrix
[Sx, Sy, Sz, Sk] = solve(A*p1_nor==p1_aff, A*p2_nor==p2_aff);
a11_d = double(Sx);
a12_d = double(Sy);
a21_d = double(Sz);
a22_d = double(Sk);
lena = imread('lena512.png');
new_aff = uint8(zeros(size(lena)));
for i = 1:size(lena,1)
for j = 1:size(lena,2)
% Applying affine transformation
new_coord = [a11_d a12_d 0; a21_d a22_d 0; 0 0 1]*[i; j; 1];
% Nearest-Neighbor interpolation for placing new pixels
if(round(new_coord(1)) > 0 && round(new_coord(2)) > 0)
new_aff(round(new_coord(1)),round(new_coord(2))) = lena(i,j);
end
end
end
imwrite(new_aff, 'lenaAffine_new.png');
At the end of above code, I get this image:
Does anyone understand what is wrong here? I am going crazy.
Two corresponding points are not enough to determine affine transformation. You need at least 6 matches (If I'm not mistaken).
Use cpselect gui to select corresponding points:
>> [input_points, base_points] = cpselect(oim2, oim1, 'Wait', true);
Then you can transform using:
>> T = cp2tform( input_points, base_points, 'affine' );
>> aim2 = tformarray( oim2, T, makeresampler('cubic','fill'), [2 1], [2 1], size(oim1(:,:,1)'), [], 0 );

Ellipse Detection using Hough Transform

using Hough Transform, how can I detect and get coordinates of (x0,y0) and "a" and "b" of an ellipse in 2D space?
This is ellipse01.bmp:
I = imread('ellipse01.bmp');
[m n] = size(I);
c=0;
for i=1:m
for j=1:n
if I(i,j)==1
c=c+1;
p(c,1)=i;
p(c,2)=j;
end
end
end
Edges=transpose(p);
Size_Ellipse = size(Edges);
B = 1:ceil(Size_Ellipse(1)/2);
Acc = zeros(length(B),1);
a1=0;a2=0;b1=0;b2=0;
Ellipse_Minor=[];Ellipse_Major=[];Ellipse_X0 = [];Ellipse_Y0 = [];
Global_Threshold = ceil(Size_Ellipse(2)/6);%Used for Major Axis Comparison
Local_Threshold = ceil(Size_Ellipse(1)/25);%Used for Minor Axis Comparison
[Y,X]=find(Edges);
Limit=numel(Y);
Thresh = 150;
Para=[];
for Count_01 =1:(Limit-1)
for Count_02 =(Count_01+1):Limit
if ((Count_02>Limit) || (Count_01>Limit))
continue
end
a1=Y(Count_01);b1=X(Count_01);
a2=Y(Count_02);b2=X(Count_02);
Dist_01 = (sqrt((a1-a2)^2+(b1-b2)^2));
if (Dist_01 >Global_Threshold)
Center_X0 = (b1+b2)/2;Center_Y0 = (a1+a2)/2;
Major = Dist_01/2.0;Alpha = atan((a2-a1)/(b2-b1));
if(Alpha == 0)
for Count_03 = 1:Limit
if( (Count_03 ~= Count_01) || (Count_03 ~= Count_02))
a3=Y(Count_03);b3=X(Count_03);
Dist_02 = (sqrt((a3 - Center_Y0)^2+(b3 - Center_X0)^2));
if(Dist_02 > Local_Threshold)
Cos_Tau = ((Major)^2 + (Dist_02)^2 - (a3-a2)^2 - (b3-b2)^2)/(2*Major*Dist_02);
Sin_Tau = 1 - (Cos_Tau)^2;
Minor_Temp = ((Major*Dist_02*Sin_Tau)^2)/(Major^2 - ((Dist_02*Cos_Tau)^2));
if((Minor_Temp>1) && (Minor_Temp<B(end)))
Acc(round(Minor_Temp)) = Acc(round(Minor_Temp))+1;
end
end
end
end
end
Minor = find(Acc == max(Acc(:)));
if(Acc(Minor)>Thresh)
Ellipse_Minor(end+1)=Minor(1);Ellipse_Major(end+1)=Major;
Ellipse_X0(end+1) = Center_X0;Ellipse_Y0(end+1) = Center_Y0;
for Count = 1:numel(X)
Para_X = ((X(Count)-Ellipse_X0(end))^2)/(Ellipse_Major(end)^2);
Para_Y = ((Y(Count)-Ellipse_Y0(end))^2)/(Ellipse_Minor(end)^2);
if (((Para_X + Para_Y)>=-2)&&((Para_X + Para_Y)<=2))
Edges(X(Count),Y(Count))=0;
end
end
end
Acc = zeros(size(Acc));
end
end
end
Although this is an old question, perhaps what I found can help someone.
The main problem of using the normal Hough Transform to detect ellipses is the dimension of the accumulator, since we would need to vote for 5 variables (the equation is explained here):
There is a very nice algorithm where the accumulator can be a simple 1D array, for example, and that runs in . If you wanna see code, you can look at here (the image used to test was that posted above).
If you use circle for rough transform is given as rho = xcos(theta) + ysin(theta)
For ellipse since it is
You could transform the equation as
rho = axcos(theta) + bysin(theta)
Although I am not sure if you use standard Hough Transform, for ellipse-like transforms, you could manipulate the first given function.
If your ellipse is as provided, being a true ellipse and not a noisy sample of points;
the search for the two furthest points gives the ends of the major axis,
the search for the two nearest points gives the ends of the minor axis,
the intersection of these lines (you can check it's a right angle) occurs at the centre.
If you know the 'a' and 'b' of an ellipse then you can rescale the image by factor of a/b in one direction and look for circle. I am still thinking about what to do when a and b are unknown.
If you know that it is circle then use Hough transform for circles. Here is a sample code:
int accomulatorResolution = 1; // for each pixel
int minDistBetweenCircles = 10; // In pixels
int cannyThresh = 20;
int accomulatorThresh = 5*_accT+1;
int minCircleRadius = 0;
int maxCircleRadius = _maxR*10;
cvClearMemStorage(storage);
circles = cvHoughCircles( gryImage, storage,
CV_HOUGH_GRADIENT, accomulatorResolution,
minDistBetweenCircles,
cannyThresh , accomulatorThresh,
minCircleRadius,maxCircleRadius );
// Draw circles
for (int i = 0; i < circles->total; i++){
float* p = (float*)cvGetSeqElem(circles,i);
// Draw center
cvCircle(dstImage, cvPoint(cvRound(p[0]),cvRound(p[1])),
1, CV_RGB(0,255,0), -1, 8, 0 );
// Draw circle
cvCircle(dstImage, cvPoint(cvRound(p[0]),cvRound(p[1])),
cvRound(p[2]),CV_RGB(255,0,0), 1, 8, 0 );
}

Resources