How to convert points in ASCII to Bytes-based format - byte

I have points in the format:
0 1 0
1 1 2
1 0 1
I need to translate them to:
HEADER
4 bytes, Number of points (N)
12 bytes, Bounding box minimum, float vec3
12 bytes, Bounding box maximum, float vec3
DATA
N * ushort vec3 = Each point is a 3D vector with fixed-point normalized components.
e.g. x stored ushort = x world * 65535.0f / (bound max x - bound min x)
I tried to use CloudCompare to export it in .ply format, but hex values didn't seem to match ASCII values.
This is needed for gvdb library described here:
https://devtalk.nvidia.com/default/topic/1031640/gvdb-voxels/any-instruction-to-the-point-cloud-dat-format-in-gpointcloud-sample-/
Any ideas really appreciated.

Related

Is there any way to compress two angles to 2 bytes?

In my application I often use data which contain two integer angles of spherical coordinates. They are phi (0 <= phi < 360 in degrees), and theta (0 <= theta <= 180 in degrees). Is there any way to compress these angles into 2 bytes? I have found solution which compresses them for 17 bits - it is enough for me, but maybe there any algorithm which allows to compress them for 16 bits? Unfortunately I don't know specific algorithms in such area (like compression theory)
Yes, you can do it: multiply the first angle phi by 181, and add the second angle theta. The result will fit in an unsigned 16-bit integer:
uint16_t compressed = 181 * phi + theta;
Given your constraints, the highest number that you are going to get is 65159 (359*181+180), which is barely under 216-1 (65535).
If the values of phi and theta are integers in your ranges, there are 360 possible values of phi and 181 possible values of theta. You can combine them into a single value between 0 and 65159 with the expression
phi * 181 + theta
Given a "compressed value of n in the range, you can get back the original values with
phi = n // 181
theta = n % 181
Note that the values will fit into an unsigned 16-bit integer, which allows 0 to 65535, but not a signed one without further processing.

please explain this equation exactly

I have this equation :
I = (I - min(I(:))) / (max(I(:)) - min(I(:)));
where I is a matrix, I know that min(I(:)) and max(I(:)) compute minimum and maximum element of the I matrix respectively.
When I make a random matrix rand(5,5) or randi(5,5) I don't see any change before and after the implement above equation:
but when I implement this equation on gray-scale image the result is binary image:
Can anyone here explain this equation exactly please?
I = (I - min(I(:))) / (max(I(:)) - min(I(:)));
The code line
I = (I - min(I(:))) / (max(I(:)) - min(I(:)));
linearly transforms data from the range [min(I(:)), max(I(:))] to the range [0, 1] – it is a form of standardization. The part before the division moves the data such that the minimal value becomes 0. Then the division squeezes the data such that the maximal value becomes 1.
You can get a feeling for what happens by plotting the original and transformed data against each other:
I = randi(100, 1, 10);
plot(I, (I - min(I(:))) / (max(I(:)) - min(I(:))), '.')
xlabel original
ylabel transformed
By chance, the minimum value was 5 and the maximum value 75. The data are linearly transformed such that the minimum is mapped to 0 and the maximum to 1.
That you don't see a difference in your matrix plots is probably due to the way you plot it. If you use e.g. imagesc, it does such a transformation internally before plotting (hence the sc part for "scaling") and so you don't see a difference. But the difference is there, just look at the numbers themselves:
Example:
>> I = randi(3, 3, 3)
I =
1 2 2
1 2 2
2 3 3
>> I = (I - min(I(:))) / (max(I(:)) - min(I(:)))
I =
0 0.5 0.5
0 0.5 0.5
0.5 1 1
The gray-scale image that you used, tire.tif from Matlab, is an 8-bit image. If you read it into Matlab
I = imread('tire.tif');
you get an array of uint8 values:
>> whos I
Name Size Bytes Class Attributes
I 205x232 47560 uint8
In Matlab, if you do computations with such an integer data type, in many cases the result stays an integer, too. You scale to [0, 1], but there are only two integers in that range. As a result you get an image that contains only 0 and 1 as values, a binary image. The effect can again be visualized by plotting:
plot(I(:), (I(:) - min(I(:))) / (max(I(:)) - min(I(:))), '.')
xlabel original
ylabel transformed
The original data are integers from 0 to 255, and they are mapped to 0 for the range 0–127, and to 1 for the range 128–255. To avoid that, first convert the data to a floating-point data type:
I = double(I);
For more information on integer arithmetic, see the Matlab documentation.

How to add a Gaussian shaped object to an image?

I am interested in adding a single Gaussian shaped object to an existing image, something like in the attached image. The base image that I would like to add the object to is 8-bit unsigned with values ranging from 0-255. The bright object in the attached image is actually a tree represented by normalized difference vegetation index (NDVI) data. The attached script is what I have have so far. How can I add a a Gaussian shaped abject (i.e. a tree) with values ranging from 110-155 to an existing NDVI image?
Sample data available here which can be used with this script to calculate NDVI
file = 'F:\path\to\fourband\image.tif';
[I R] = geotiffread(file);
outputdir = 'F:\path\to\output\directory\'
%% Make NDVI calculations
NIR = im2single(I(:,:,4));
red = im2single(I(:,:,1));
ndvi = (NIR - red) ./ (NIR + red);
ndvi = double(ndvi);
%% Stretch NDVI to 0-255 and convert to 8-bit unsigned integer
ndvi = floor((ndvi + 1) * 128); % [-1 1] -> [0 256]
ndvi(ndvi < 0) = 0; % not really necessary, just in case & for symmetry
ndvi(ndvi > 255) = 255; % in case the original value was exactly 1
ndvi = uint8(ndvi); % change data type from double to uint8
%% Need to add a random tree in the image here
%% Write to geotiff
tiffdata = geotiffinfo(file);
outfilename = [outputdir 'ndvi_' '.tif'];
geotiffwrite(outfilename, ndvi, R, 'GeoKeyDirectoryTag', tiffdata.GeoTIFFTags.GeoKeyDirectoryTag)
Your post is asking how to do three things:
How do we generate a Gaussian shaped object?
How can we do this so that the values range between 110 - 155?
How do we place this in our image?
Let's answer each one separately, where the order of each question builds on the knowledge from the previous questions.
How do we generate a Gaussian shaped object?
You can use fspecial from the Image Processing Toolbox to generate a Gaussian for you:
mask = fspecial('gaussian', hsize, sigma);
hsize specifies the size of your Gaussian. You have not specified it here in your question, so I'm assuming you will want to play around with this yourself. This will produce a hsize x hsize Gaussian matrix. sigma is the standard deviation of your Gaussian distribution. Again, you have also not specified what this is. sigma and hsize go hand-in-hand. Referring to my previous post on how to determine sigma, it is generally a good rule to set the standard deviation of your mask to be set to the 3-sigma rule. As such, once you set hsize, you can calculate sigma to be:
sigma = (hsize-1) / 6;
As such, figure out what hsize is, then calculate your sigma. After, invoke fspecial like I did above. It's generally a good idea to make hsize an odd integer. The reason why is because when we finally place this in your image, the syntax to do this will allow your mask to be symmetrically placed. I'll talk about this when we get to the last question.
How can we do this so that the values range between 110 - 155?
We can do this by adjusting the values within mask so that the minimum is 110 while the maximum is 155. This can be done by:
%// Adjust so that values are between 0 and 1
maskAdjust = (mask - min(mask(:))) / (max(mask(:)) - min(mask(:)));
%//Scale by 45 so the range goes between 0 and 45
%//Cast to uint8 to make this compatible for your image
maskAdjust = uint8(45*maskAdjust);
%// Add 110 to every value to range goes between 110 - 155
maskAdjust = maskAdjust + 110;
In general, if you want to adjust the values within your Gaussian mask so that it goes from [a,b], you would normalize between 0 and 1 first, then do:
maskAdjust = uint8((b-a)*maskAdjust) + a;
You'll notice that we cast this mask to uint8. The reason we do this is to make the mask compatible to be placed in your image.
How do we place this in our image?
All you have to do is figure out the row and column you would like the centre of the Gaussian mask to be placed. Let's assume these variables are stored in row and col. As such, assuming you want to place this in ndvi, all you have to do is the following:
hsizeHalf = floor(hsize/2); %// hsize being odd is important
%// Place Gaussian shape in our image
ndvi(row - hsizeHalf : row + hsizeHalf, col - hsizeHalf : col + hsizeHalf) = maskAdjust;
The reason why hsize should be odd is to allow an even placement of the shape in the image. For example, if the mask size is 5 x 5, then the above syntax for ndvi simplifies to:
ndvi(row-2:row+2, col-2:col+2) = maskAdjust;
From the centre of the mask, it stretches 2 rows above and 2 rows below. The columns stretch from 2 columns to the left to 2 columns to the right. If the mask size was even, then we would have an ambiguous choice on how we should place the mask. If the mask size was 4 x 4 as an example, should we choose the second row, or third row as the centre axis? As such, to simplify things, make sure that the size of your mask is odd, or mod(hsize,2) == 1.
This should hopefully and adequately answer your questions. Good luck!

Find maximum pixel using BLOCKPROC in Matlab

In Matlab I've got a 3D matrix (over 100 frames 512x512). My goal is to find some representative points through the whole hyper-matrix. To do so I've implemented the traditional (and not very efficient) method: I subdivide the large matrix into smaller sub-matrices and then I look for the pixel with the highest value. After doing that I change those relative coordinates of that very pixel in the sub-matrix to global coordinates referenced to the large matrix.
Now, I'm redesigning the algorithm. I've seen that in order to analyze a large matrix block-by-block (that's actually what I'm doing with my old algorithm) the BLOCKPROC function is very efficient. I've read the documentation but I don't know how the "fun" function should be implemented to extract that the pixel with the highest value of each block. Thank you in advance.
*I'm trying to get the coordinates of those maximum pixels referenced to the global matrix, I really don't care about their value.
First define a function to find the location of the maximum of a (sub)matrix:
function loc = max_location(M);
[~, ii] = max(M(:));
[r c] = ind2sub(size(M),ii);
loc = [r c];
Then use
blockproc(im, blocksize, #(x) x.location+max_location(x.data)-1)
where im is your image (2D array) and blocksize is a 1x2 vector specifying block size. Within blockproc, the data field is the submatrix (which you pass to max_location), and the location field contains the coordinates of the top-left corner of the submatrix (which you add to the result of max_location, minus 1).
Example:
>> blocksize = [3 3];
>> im = [ 0.3724 0.0527 0.4177 0.6981 0.0326 0.4607
0.1981 0.7379 0.9831 0.6665 0.5612 0.9816
0.4897 0.2691 0.3015 0.1781 0.8819 0.1564
0.3395 0.4228 0.7011 0.1280 0.6692 0.8555
0.9516 0.5479 0.6663 0.9991 0.1904 0.6448
0.9203 0.9427 0.5391 0.1711 0.3689 0.3763 ];
>> blockproc(im, blocksize, #(x) x.location+max_location(x.data)-1)
ans =
2 3 2 6
5 1 5 4
meaning your block maxima are located at coordinates (2,3), (5,1), (2,6) and (5,4)
Another possiblity is to use im2col for each frame. If I is your frame (512,512):
% rearranges 512 x 512 image into 4096 x 64
% each column of I2 represents a 64 x 64 block
n = 64;
I2 = im2col(I,[n,n],'distinct');
% find max in each block
% ~ to ignore that output
[~,y] = max(I2);
% convert those values to overall indices
ind = sub2ind(size(I2),y, 1:n);
% create new matrix
I3 = zeros(size(I2));
I3(ind)=1;
I3 = col2im(I3,[n,n],size(I),'distinct');
I3 should now be an image the same size of input I but with all zeros except for the locations of the maximum points in each sub-matrix.
the tricky part with the function handle "fun" is that it refers to the subblocks which are a struct, this is an object with one or more fields and one or more values assigend to each of the fields.
The values of your subblocks are stored in a field called "data" so the function call
#(x)max(x)
is not enough, in this case the correct version of that is
#(x)max(x.data)
A 2D example of what you are looking for would look like this:
a=magic(4);
b=blockproc(a,[2,2],#(x) find(x.data==max(max(x.data)))); %linear indexes
outputs
a =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
b =
1 3
4 2
b are the linear indexes of each subblock, so that's the values 16, 13, 14, 15 in a.
Hope that helps!

Implementing a Hilbert map of the Internet

In the XKCD comic 195 a design for a map of the Internet address space is suggested using a Hilbert curve so that items from a similar IP adresses will be clustered together.
Given an IP address, how would I calculate its 2D coordinates (in the range zero to one) on such a map?
This is pretty easy, since the Hilbert curve is a fractal, that is, it is recursive. It works by bisecting each square horizontally and vertically, dividing it into four pieces. So you take two bits of the IP address at a time, starting from the left, and use those to determine the quadrant, then continue, using the next two bits, with that quadrant instead of the whole square, and so on until you have exhausted all the bits in the address.
The basic shape of the curve in each square is horseshoe-like:
0 3
1 2
where the numbers correspond to the top two bits and therefore determine the traversal order. In the xkcd map, this square is the traversal order at the highest level. Possibly rotated and/or reflected, this shape is present at each 2x2 square.
Determination of how the "horseshoe" is oriented in each of the subsquares is determined by one rule: the 0 corner of the 0 square is in the corner of the larger square. Thus, the subsquare corresponding to 0 above must be traversed in the order
0 1
3 2
and, looking at the whole previous square and showing four bits, we get the following shape for the next division of the square:
00 01 32 33
03 02 31 30
10 13 20 23
11 12 21 22
This is how the square always gets divided at the next level. Now, to continue, just focus on the latter two bits, orient this more detailed shape according to how the horseshoe shape of those bits is oriented, and continue with a similar division.
To determine the actual coordinates, each two bits determine one bit of binary precision in the real number coordinates. So, on the first level, the first bit after the binary point (assuming coordinates in the [0,1] range) in the x coordinate is 0 if the first two bits of the address have the value 0 or 1, and 1 otherwise. Similarly, the first bit in the y coordinate is 0 if the first two bits have the value 1 or 2. To determine whether to add a 0 or 1 bit to the coordinates, you need to check the orientation of the horseshoe at that level.
EDIT: I started working out the algorithm and it turns out that it's not that hard after all, so here's some pseudo-C. It's pseudo because I use a b suffix for binary constants and treat integers as arrays of bits, but changing it to proper C shouldn't be too hard.
In the code, pos is a 3-bit integer for the orientation. The first two bits are the x and y coordinates of 0 in the square and the third bit indicates whether 1 has the same x coordinate as 0. The initial value of pos is 011b, meaning that the coordinates of 0 are (0, 1) and 1 has the same x coordinate as 0. ad is the address, treated as an n-element array of 2-bit integers, and starting from the most significant bits.
double x = 0.0, y = 0.0;
double xinc, yinc;
pos = 011b;
for (int i = 0; i < n; i++) {
switch (ad[i]) {
case 0: xinc = pos[0]; yinc = pos[1]; pos[2] = ~pos[2]; break;
case 1: xinc = pos[0] ^ ~pos[2]; yinc = pos[1] ^ pos[2]; break;
case 2: xinc = ~pos[0]; yinc = ~pos[1]; break;
case 3: xinc = pos[0] ^ pos[2]; yinc = pos[1] ^ ~pos[2];
pos = ~pos; break;
}
x += xinc / (1 << (i+1)); y += yinc / (1 << (i+1));
}
I tested it with a couple of 8-bit prefixes and it placed them correctly according to the xkcd map, so I'm somewhat confident the code is correct.
Essentially you would decompose the number, using pairs of bits, MSB to LSB. The pair of bits tells you if the location is in the Upper Left (0) Lower Left (1) Lower Right (2) or Upper Right (3) quadrant, at a scale that gets finer as you shift through the number.
Additionally, you need to track an "orientation". This is the winding that is used at the scale you are at; the initial winding is as above (UL, LL, LR, UR), and depending on which quadrant you end up in, the winding at the next scale down is (rotated -90, 0, 0, +90) from your current winding.
So you could accumulate offsets :
suppose I start at 0,0, and the first pair gives me a 2, I shift offsets to 0.5, 0.5. The winding in the lower right is the same as my initial one. The next pair reduces the scale, so my adjustments are going to be 0.25 in length.
This pair is a 3, so I translate only my x coordinate and I am at .75, .5. The winding is now rotated over and my next scale down will be (LR, LL, UL, UR). The scale is now .125, and so on and so on until I run out of bits in my address.
I expect that based on the wikipedia code for a Hilbert curve you could keep track of your current position (as an (x, y) coordinate) and return that position after n cells had been visited. Then the position scaled onto [0..1] would depend on how high and wide the Hilbert curve was going to be at completion.
from turtle import left, right, forward
size = 10
def hilbert(level, angle):
if level:
right(angle)
hilbert(level - 1, -angle)
forward(size)
left(angle)
hilbert(level - 1, angle)
forward(size)
hilbert(level - 1, angle)
left(angle)
forward(size)
hilbert(level - 1, -angle)
right(angle)
Admittedly, this would be a brute force solution rather than a closed form solution.

Resources