I was experimenting with GameplayKit’s GKAgent3D class to move a SCNNode within a scene. I was able to update the SCNNode with the agent’s position, but not rotation. The issue being the agent’s rotation is stored as a matrix_float3x3, which doesn’t match any of data types SceneKit uses for storing rotational information.
So what I’d like to know is if there’s a simple function or method that could convert a rotation stored as matrix_float3x3 to any SceneKit data types?
To expand on #rickster 's answer, here's a nice way to take the top-left 3x3 of a 4x4 matrix in Swift, taking advantage of the expanded simd support in the iOS 11/ tvOS 11/ High Sierra version of SceneKit:
extension float4 {
var xyz: float3 {
return float3(x, y, z)
}
init(_ vec3: float3, _ w: Float) {
self = float4(vec3.x, vec3.y, vec3.z, w)
}
}
extension float4x4 {
var upperLeft3x3: float3x3 {
let (a,b,c,_) = columns
return float3x3(a.xyz, b.xyz, c.xyz)
}
init(rotation: float3x3, position: float3) {
let (a,b,c) = rotation.columns
self = float4x4(float4(a, 0),
float4(b, 0),
float4(c, 0),
float4(position, 1))
}
}
Then, to update your agent to match your node's orientation, you'd write:
agent.rotation = node.simdTransform.upperLeft3x3
Or, if the node in question is not at the "root" level (as in, a direct child of the rootNode), you might want to use the node's worldTransform:
agent.rotation = node.simdWorldTransform.upperLeft3x3
EDIT: If the node in question has a dynamic physics body attached, or is being animated with an SCNTransaction block, the node's presentation node will more accurately reflect its current position on screen:
agent.position = node.presentation.simdWorldPosition
agent.rotation = node.presentation.simdWorldTransform.upperLeft3x3
EDIT: added code above for going in the other direction, moving the node to match the agent.
node.simdTransform = float4x4(rotation: agent3d.rotation, position: agent3d.position)
Note that if you have a physics body attached to the node, it should be kinematic rather than dynamic if you're going to be directly modifying the node's transform in this way.
SceneKit takes transform matrices as SCNMatrix4, and provides utilities for converting from SIMD matrix_float4x4: init(_ m: float4x4) for Swift and SCNMatrix4FromMat4 for ObjC/C++.
Sadly, I don't see a built-in way to convert between SIMD 3x3 and 4x4 matrices using the assumption that the 3x3 is the upper left of the 4x4. (Seems like you'd expect that in the SIMD library, so it's worth filing a bug to Apple about.)
But it's not too hard to provide one yourself: just construct a 4x4 from column vectors, using the three column vectors of the 3x3 (padded out to float4 vectors with zero for the w component) and identity for the fourth column (0,0,0,1). (Implementation code left for the reader, partly because I don't want to write it for three languages.) After converting float3x3 to float4x4 you can convert to SCNMatrix4.
Edit: In iOS 11 / tvOS 11 / macOS 10.13 (why didn't they just call this year's macOS version 11, too?), SceneKit has a whole parallel set of APIs for using SIMD types like float4x4 directly; e.g. simdTransform. However, you still need to convert a 3x3 to a 4x4 matrix.
Related
if i have a setup where in order to transform a bone, I have to:
node.transform = scale(node.transform, 2, 2, 2)
then
bone_transform = inverse:offset_matrix *
(node.parent.transform * node.transform) * (inverse:node.parent.transform) * offset_matrix
However this only works properly for bones that doesn't have any children (or the bottom-most in the node hierarchy)..
therefore having trouble when traversing through the bones part..
how would I do this correctly to get the correct bone_transform for all bones..
So if I want to transform any bone anywhere in the hierarchy (using node.transform), it would also adjust all its children bone_transforms correctly..
maybe something like:
mat4 transform = node.transform
while (node.parent != 0) {
if (node.is_bone) {
transform = node.parent.transform * node.transform
}
node = node.parent
}
or something with node.children recursively?
The offset-matrix is already the global transformation for your bone. It contains already all the transformation data from the root down to your current bone.
That is the reason that your code only works for bones without any parent nodes.
I have built a sparse matrix mat from a list of triplets
Eigen::SparseMatrix<double, Eigen::RowMajor> mat(Nbins,Ndata);
mat.setFromTriplets(tripletList.begin(), tripletList.end());
Now I would like to create a new matrix ret, which only contains the rows of the previous matrix which are not empty. I do it as follows
Eigen::SparseMatrix<double, Eigen::RowMajor> ret(Nbins,Ndata);
unsigned Nrow=0;
for (unsigned i=0; i<Nbins; ++i) {
auto mrow = mat.row(i);
if (mrow.sum()>0) {
ret.row(Nrow++) = mrow;
}
}
ret.conservativeResize(Nrow,Ndata);
However, doing it this way is slow and inefficient. Slow because quick profiling suggests it spends most of its time on ret.row(Nrow++) = mrow;. Inefficient because we are also copying all the data twice.
Is there a better solution? I feel one has to fiddle with the inner vectors but I get confused by them and I don't know how user-proof it is to play with them.
EDIT: In my application, matrices are row major, and I want to remove empty rows. mat is not needed, just ret. All coefficients are positive hence the way I check for nonzero rows. The triplets are sorted but column-major. There are no duplicate triplets.
Found it! Instead of writing a hand-made setFromTriplets, I went with a modification of the tripletList. The interface of Eigen::Triplet makes it very easy.
//get which rows are empty
std::vector<bool> has_value(Nbins,false);
for (auto tr : tripletList) has_value[tr.row()] = true;
//create map from old to new indices
std::map<unsigned,unsigned> row_map;
unsigned new_idx=0;
for (unsigned old_idx=0; old_idx<Nbins; old_idx++)
if(has_value[old_idx])
row_map[old_idx]=new_idx++;
//make new triplet list, dropping empty rows
std::vector<Eigen::Triplet<double> > newTripletList;
newTripletList.reserve(Ndata);
for (auto tr : tripletList)
newTripletList.push_back(
Eigen::Triplet<double>(row_map[tr.row()],tr.col(),tr.value()));
//form new matrix and return
Eigen::SparseMatrix<double, Eigen::RowMajor> ret(new_idx,Ndata);
ret.setFromTriplets(newTripletList.begin(), newTripletList.end());
first of all, I'm totally new to kivy, so I'm struggling a bit.
I'm trying to display a numpy array in a kivy window.
So far i figured out that this should work using the Texture Class (http://kivy.org/docs/api-kivy.graphics.texture.html).
As my numpy array changes from time to time, I'm trying to adjust the following code to my application.
# create a 64x64 texture, defaults to rgb / ubyte
texture = Texture.create(size=(64, 64))
# create 64x64 rgb tab, and fill with values from 0 to 255
# we'll have a gradient from black to white
size = 64 * 64 * 3
buf = [int(x * 255 / size) for x in range(size)]
# then, convert the array to a ubyte string
buf = b''.join(map(chr, buf))
# then blit the buffer
texture.blit_buffer(buf, colorfmt='rgb', bufferfmt='ubyte')
# that's all ! you can use it in your graphics now :)
# if self is a widget, you can do this
with self.canvas:
Rectangle(texture=texture, pos=self.pos, size=(64, 64))
It seems that creating the texture and changing it works as it should, but i dont get, how to display the texture.
Can anybody explain to me, how to use the
with self.canvas:
Rectangle(texture=texture, pos=self.pos, size=(64, 64))
in a way, that I get to see my picture/numpy array.
Thanks alot in advance!
Holzroller
Edit:
I figured out that using Kivy 1.8.0 and the Texture Class is a bit messy. So I upgraded to Kivy 1.9.0 via github (installing Kivy via apt-get in Ubuntu 14.04 LTS serves you the 1.8.0 version) and I get to see the Texture using the following code. I hope that helps people who are having the same problem as me.
from kivy.graphics.texture import Texture
from kivy.graphics import Rectangle
from kivy.uix.widget import Widget
from kivy.base import runTouchApp
from array import array
from kivy.core.window import Window
# create a 64x64 texture, defaults to rgb / ubyte
texture = Texture.create(size=(1280, 1024), colorfmt='rgb')
# create 64x64 rgb tab, and fill with values from 0 to 255
# we'll have a gradient from black to white
size = 1280 * 1024 * 3
buf = [int(x * 255 / size) for x in range(size)]
# then, convert the array to a ubyte string
arr = array('B', buf)
# buf = b''.join(map(chr, buf))
# then blit the buffer
texture.blit_buffer(arr, colorfmt='rgb', bufferfmt='ubyte')
# that's all ! you can use it in your graphics now :)
# if self is a widget, you can do this
root = Widget()
with root.canvas:
Rectangle(texture=texture, pos=(0, 0), size=(1280*3, 1024*3))
runTouchApp(root)
Edit2:
Basically I'm back to the original Problem:
I have a numpy array (type 'numpy.ndarray'; dtype 'uint8') and I'm trying to convert it into a format, so that the texture will show me the image. I tried to break it down to the same way it is done in the example code i posted above. But i sadly doesn't work. I really do not know what I'm doing wrong here.
(my numpy array is called im2 in the folling code)
list1 = numpy.array(im2).reshape(-1,).tolist()
arr = array('B', list1)
texture.blit_buffer(arr, colorfmt='rgb', bufferfmt='ubyte')
Numpy have a tostring() attribute, that you could use directly, if the source array is uint8 type. You don't even need to reshape:
texture = Texture.create(size=(16, 16), colorfmt="rgb"))
arr = numpy.ndarray(shape=[16, 16, 3], dtype=numpy.uint8)
# fill your numpy array here
data = arr.tostring()
texture.blit_buffer(data, bufferfmt="ubyte", colorfmt="rgb"
About the issue you're talking in the comment, i see 2 points:
Ensure the callback from the ROS is called in the mainthread. Maybe the update is simply ignored.
When you manually change inplace the texture, the associated object that use it are not notified, you need to do it. Add a self.canvas.ask_update() to ensure the canvas redisplay at the next frame.
Currently, I am using a convex hull algorithm to get the outer most points from a set of points randomly placed. What I aim to do is draw a polygon from the set of points returned by the convex hull however, when I try to draw the polygon it looks quite strange.
My question, how do I order the points so the polygon draws correctly?
Thanks.
EDIT:
Also, I have tried sorting using orderby(...).ThenBy(...) and I cant seem to get it working.
Have you tried the gift wrapping algorithm ( http://en.wikipedia.org/wiki/Gift_wrapping_algorithm)? This should return points in the correct order.
I had an issue where a random set of points were generated from which a wrapped elevation vector needed a base contour. Having read the link supplied by #user1149913 and found a sample of gift-wrapping a hull, the following is a sample of my implementation:
private static PointCollection CalculateContour (List<Point> points) {
// locate lower-leftmost point
int hull = 0;
int i;
for (i = 1 ; i < points.Count ; i++) {
if (ComparePoint(points[i], points[hull])) {
hull = i;
}
}
// wrap contour
var outIndices = new int[points.Count];
int endPt;
i = 0;
do {
outIndices[i++] = hull;
endPt = 0;
for (int j = 1 ; j < points.Count ; j++)
if (hull == endPt || IsLeft(points[hull], points[endPt], points[j]))
endPt = j;
hull = endPt;
} while (endPt != outIndices[0]);
// build countour points
var contourPoints = new PointCollection(points.Capacity);
int results = i;
for (i = 0 ; i < results ; i++)
contourPoints.Add(points[outIndices[i]]);
return contourPoints;
}
This is not a full solution but a guide in the right direction. I faced a very similar problem just recently and I found a reddit post with an answer (https://www.reddit.com/r/DnDBehindTheScreen/comments/8efeta/a_random_star_chart_generator/dxvlsyt/) suggesting to use Delaunay triangulation which basically returns a solution with all possible triangles made within the data points you have. Once you have all possible triangles, which by definition you know won't result on any overlapped lines, you can chose which lines you use which result on all nodes being connected.
I was coding my solution on python and fortunately there's lots of scientific libraries on python. I was working on a random sky chart generator which would draw constellations out of those stars. In order to get all possible triangles (and draw them, just for fun), before going into the algorithm to draw the actual constellations, all I had to do was this:
# 2D array of the coordinates of every star generated randomly before
points = list(points_dict.keys())
from scipy.spatial import Delaunay
tri = Delaunay(points)
# Draw the debug constellation with the full array of lines
debug_constellation = Constellation(quadrants = quadrants, name_display_style = config.constellation_name_display_style)
for star in available_stars:
debug_constellation.add_star(star)
for triangle in tri.simplices:
star_ids = []
for index in triangle:
star_ids.append(points_dict[points[index]].id)
debug_constellation.draw_segment(star_ids, is_closed = True)
# Code to generate the image follows below
You can see the full implementation here: fake_sky_chart_generator/fake_libs/constellation_algorithms/delaunay.py
This is the result:
I'm just trying to adjust contrast/ brightness in an image in gray scale to highlight whites in that image with Opencv in C. How can I do that? is there any function that makes this task in opencv?
Original image:
Modified image:
Thanks in advance!
I think you can adjust contrast here in two ways:
1) Histogram Equalization :
But when i tried this with your image, result was not as you expected. Check it below:
2) Thresholding :
Here, i compared each pixel value of input with an arbitrary value ( which i took 127). Below is the logic which has inbuilt function in opencv. But remember, output is Binary image, not grayscale as you did.
If (input pixel value >= 127):
ouput pixel value = 255
else:
output pixel value = 0
And below is the result i got :
For this, you can use Threshold function or compare function
3) If you are compulsory to get grayscale image as output, do as follows:
(code is in OpenCV-Python, but for every-function, corresponding C functions are available in opencv.itseez.com)
for each pixel in image:
if pixel value >= 127: add 'x' to pixel value.
else : subtract 'x' from pixel value.
( 'x' is an arbitrary value.) Thus difference between light and dark pixels increases.
img = cv2.imread('brain.jpg',0)
bigmask = cv2.compare(img,np.uint8([127]),cv2.CMP_GE)
smallmask = cv2.bitwise_not(bigmask)
x = np.uint8([90])
big = cv2.add(img,x,mask = bigmask)
small = cv2.subtract(img,x,mask = smallmask)
res = cv2.add(big,small)
And below is the result obtained:
You could also check out the OpenCV CLAHE algorithm. Instead of equalizing the histogram globally, it splits up the image into tiles and equalizes those locally, then stitches them together. This can give a much better result.
With your image in OpenCV 3.0.0:
import cv2
inp = cv2.imread('inp.jpg',0)
clahe = cv2.createCLAHE(clipLimit=4.0, tileGridSize=(8,8))
res = clahe.apply(inp)
cv2.imwrite('res.jpg', res)
Gives something pretty nice
Read more about it here, though it's not super helpful:
http://docs.opencv.org/3.1.0/d5/daf/tutorial_py_histogram_equalization.html#gsc.tab=0
Although this post is a bit aged:
What about using "cvAddWeighted( )" ?
What it does is:
dst = src1*alpha + src2*beta + gamma
What I understand from applying brightness and contrast is, that one wants to do:
dst = src*contrast + brightness;
so if
src1 = input image
src2 = any image of same type as src1
alpha = contrast value
beta = 0.0
gamma = brightness value
dst = resulting Image (must be of same type as src1)
One should be pretty much done with the task, no?
This approch works for me using CvMat* images