360 panorama image quality problem in three - three.js

We implement panorama 360 in our project. We load 9000x4500px textures (360 image). The problem appears on some resolutions, e.g. on 1920x1080, it is quite legible (in adjust zoom 75%), when we zoom to 100/125%, we start to pixelose.
enter image description here
The biggest problem appears at the resolutions of 1536x864 (125% adjust zoom) and 1280x800 then the image is practically blurry.
enter image description here
If I use a panorama viewer, the image behaves very well and these problems do not occur.
https://renderstuff.com/tools/360-panorama-web-viewer/
I will just add that I have a few points on the panorama that are clicked and some information pops up.
We used react-three-fiber
function Dome() {
const texture = new THREE.TextureLoader().load(
"../models/innerOkaglak-v4.jpg"
);
texture.mapping = EquirectangularReflectionMapping;
texture.encoding = sRGBEncoding;
texture.generateMipmaps = false;
texture.minFilter = LinearMipMapLinearFilter;
return (
<mesh>
<sphereBufferGeometry attach="geometry" args={[500, 60, 30]} />
<meshBasicMaterial
attach="material"
map={texture}
side={THREE.BackSide}
/>
</mesh>
);
}

Related

How to use x2 canvas elements and rendering paper.js on img capture of html5 video to base64

Still very much a newbie to coding, so please be gentle :)
I'm hoping someone might be able to help how to use Paper.js on a second canvas after the first one has been executed?
I'm trying to use x2 canvas elements:
Canvas 1 - to capture a html5 video image still and convert to base64 (tick :-) = done)
Canvas 2 - Use the base64 image and perform the 'Working with Rasters to find the colors of pixels' and convert to circle paths (boo = fail :-( )
Something like this:
The code:
<script src="https://cdn.jsdelivr.net/npm/hls.js#latest"></script>
<video id="video" preload="auto" muted="" playsinline="" width="580" src="blob:https://www.georgefisher.co.uk/78e3a45c-ae07-4ea5-af56-45a5ed9cf1b0"></video>
<script>
var video = document.getElementById('video');
var videoSrc = 'https://camsecure.co/HLS/georgefisher.m3u8';
if (Hls.isSupported()) {
var hls = new Hls();
hls.loadSource(videoSrc);
hls.attachMedia(video);
}
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = videoSrc;
}
video.play()
</script>
<br>
<button onclick="capture()">Capture</button>
<br>
<canvas id="canvas" style="overflow:auto">
</canvas>
<canvas id="canvas2" resize>
<img src="" id="myImg"/></canvas>
var resultb64="";
function capture() {
var canvas = document.getElementById('canvas');
var video = document.getElementById('video');
canvas.width = video.videoWidth/4;
canvas.height = video.videoHeight/4;
canvas.getContext('2d').drawImage(video, 0, 0, video.videoWidth/4, video.videoHeight/4);
resultb64=canvas.toDataURL();
document.querySelector("#myImg").src = canvas.toDataURL();
}
/*Paper JS Setup for working in CodePen */
/* ====================== *
* 0. Initiate Canvas *
* ====================== */
// expose paperjs classes into global scope
paper.install(window);
// Only executed our code once the DOM is ready.
window.onload = function() {
// bind paper to the canvas
paper.setup('canvas2');
// paper.activate();
// Get a reference to the canvas object
var canvas = document.getElementById('canvas2');
var ctx = canvas.getContext('2d');
// console.log(ctx, image);
// ctx.drawImage(image, 0, 0);
// return;
// }
// Create a raster item using the image id='' tag
var image = document.querySelector('img');
var raster = new Raster(image);
// Hide the raster:
raster.visible = false;
// The size of our grid cells:
var gridSize = 15;
// Space the cells by 120%:
var spacing = 1
;
// As the web is asynchronous, we need to wait for the raster to load before we can perform any operation on its pixels.
raster.onLoad = function() {
// Since the example image we're using is much too large, and therefore has way too many pixels, lets downsize it to 40 pixels wide and 30 pixels high:
raster.size = new Size(40, 30);
for (var y = 0; y < raster.height; y++) {
for(var x = 0; x < raster.width; x++) {
// Get the color of the pixel:
var color = raster.getPixel(x, y);
// Create a circle shaped path:
var path = new Path.Circle({
center: new Point(x, y).multiply(gridSize),
radius: gridSize / 2 / spacing,
});
// Set the fill color of the path to the color
// of the pixel:
path.fillColor = color;
}
}
// Move the active layer to the center of the view, so all the created paths in it appear centered.
project.activeLayer.position = view.center;
}
}
I've tried giving the second canvas a different Id="canvas2" and referencing that, which I can see in the console. However, nothing appears in the second canvas and the paper.js script doesn't seem to execute, can someone help me understand why?
Please see also see link to the fiddle below:
https://jsfiddle.net/jmnes/o4Lpkfs6/1/
Alternatives method.
You don't need to capture the video, you don't need to capture the pixels using paper.js and raster. You don't need to find the color of each circle and draw it.
All these methods are slow, complex, and power hungry.
You can create a mask and mask out the circles, with the colors drawn from a smaller canvas with a res that matches the number off circles.
How to
Add one (main canvas) canvas to the DOM. This will display the result
Create 2 offscreen canvas.
One (color canvas) has the same resolution as the circles you want to display. Eg if you have 30 by 40 circle the canvas res should be 30 by 40
One (mask canvas) is the circle mask. It is the same resolution as the main canvas. Draw the circles all in one color on this canvas.
Then rendering once a frame
Draw the video on the color canvas to fit.
Turn off smoothing on the main canvas eg ctxMain.imageSmoothingEnabled = false
Draw the color canvas onto the main canvas to fit.
This will draw a color square at each circle position. ctx.drawImage(colorCanvas, 0, 0, mainCanvas.width, mainCanvas.height)
Set composite operation "destination-in" eg ctxMain.globalCompositeOperation = "destination-in"
Draw the mask canvas (canvas with circles on it) onto the main canvas. This will remove pixels outside each circle.
Restore default composite operation for the main canvas ctxMain.globalCompositeOperation = "source-over"
All done for a real-time FX on almost any device.
The above methods is the fastest way to render the effect you are after using the 2D API

Image when rotated does not respect the height and width of the parent container

I have a UWP application where I am rotating an image to a 90 degree angle. I have this image and a Canvas inside a Grid because I want Canvas to be on top of the image so from the code I can create some thumb controls and do a drag an drop.
If I don't apply the rotate transform the image is aligned properly inside the Grid like shown below.
On the other hand if I specify a Rotate Transform, the image rotates but it never scales to the height and width of the container as shown below.
I saw this post here Rotating and scaling image but I don't know how to get it to work in UWP. Please help. Here is my xaml. Ultimately what I want is, after the image has been rotated it should fit to the dimensions of the Grid scaling the height and width.
Edit: Please see the solution here, that is exactly what I want in UWP. fit image height and width after rotating WPF
<Grid x:Name="gridBarImagePanel" Grid.Row="4" BorderBrush="Black" BorderThickness="2"
Height="476" Width="625">
<Image x:Name="BarCodeImage" Source="..\SampleImage\demo.png"
RenderTransformOrigin="0.54,0.40" Height="476" Width="625">
<Image.RenderTransform>
<RotateTransform Angle="90"></RotateTransform>
</Image.RenderTransform>
</Image>
<Canvas x:Name="cnvBarCodeImage" Canvas.ZIndex="100" VerticalAlignment="Stretch">
</Canvas>
</Grid>
Image when rotated does not respect the height and width of the parent container
RotateTransform is used to rotate transform uwp XAML. A RotateTransform is defined by an Angle that rotates an object through an arc around the point enterX, CenterY. But a transform is typically used to fill the UIElement.RenderTransform property and keep aspect ratio. For your scenario, we need use BitmapDecoder to re-render the image and keep aspect ratio. Please refer the following code.
private async void AppBarButton_Click(object sender, RoutedEventArgs e)
{
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/test.jpg"));
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read),
memStream = new InMemoryRandomAccessStream())
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
uint originalWidth = decoder.PixelWidth;
uint originalHeight = decoder.PixelHeight;
BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(memStream, decoder);
encoder.BitmapTransform.ScaledWidth = (uint)(originalHeight * 1.0);
encoder.BitmapTransform.ScaledHeight = (uint)(originalWidth * 1.0);
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Linear;
//Rotate 180
encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise90Degrees;
await encoder.FlushAsync();
memStream.Seek(0);
fileStream.Seek(0);
fileStream.Size = 0;
var bitmap = new BitmapImage();
bitmap.SetSource(memStream);
MyImg.Source = bitmap;
}
}
Please note: if we rotate image to 90 ° and keep aspect ratio, the image will be distortion.

JavaFX How to crop image once for multiple aspect ratios

I'm creating a desktop application in JavaFX which enables the user to search for people in different categories. There is a screen which shows each category as a tile with an image (Aspect ratio 1:1). When you click on a tile it opens another page and the image from the tile should now be displayed as the background image (Aspect ratio 16:9). The images are selected by an admin user, so it must be cropped because it could be too large, have a wrong aspect ratio and so on.
I wonder how to set up an easy way to enable the admin user to select the picture he wants, without having to crop the image twice (once as 1:1 and once as 16:9). I thought about crop only to 1:1 and then for displaying as 16:9 just zooming the picture, but this leads to bad quality if the resolution isn't high enough.
For cropping I'm referencing to this post from Roland:
How to make a Javafx Image Crop App
For background images you can simply specify that the image should cover the Region.
ImageView allows you to specify a viewport allowing you to specify the region of the Image that should be displayed. If chosen accordingly this does the croping for you.
The following code uses the same ratio for both for simplicity's sake:
#Override
public void start(Stage primaryStage) {
final Image image = new Image(URL);
// size to use for both nodes
double targetHeight = 400;
double targetWidth = targetHeight * 16 / 9;
ImageView imageView = new ImageView(image);
imageView.setFitWidth(targetWidth);
imageView.setFitHeight(targetHeight);
// calculate viewport
imageView.setViewport((image.getHeight() / targetHeight < image.getWidth() / targetWidth)
? new Rectangle2D(0, 0, image.getHeight() / targetHeight * targetWidth, image.getHeight())
: new Rectangle2D(0, 0, image.getWidth(), image.getWidth() / targetWidth * targetHeight));
Region backgroundRegion = new Region();
backgroundRegion.setPrefSize(targetWidth, targetHeight);
backgroundRegion.setBackground(new Background(
new BackgroundImage(
image,
BackgroundRepeat.NO_REPEAT,
BackgroundRepeat.NO_REPEAT,
BackgroundPosition.CENTER,
new BackgroundSize(0, 0, false, false, false, true) // cover
)));
HBox root = new HBox(imageView, backgroundRegion);
root.setFillHeight(false);
root.setPadding(new Insets(20));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

how to reset the axix of HTML5 Canvas

I am very new to html5.
infact this is my first work.
I am working on a small project. Part of the project is to read an xml file which has shapes in it
<Graphic>
<object_type>LINE</object_type>
<field_1>3.6082475185394287</field_1>
<field_2>541.23712158203125</field_2>
<field_3>28.86598014831543</field_3>
<field_4>474.48452758789062</field_4>
<field_6 />
<field_7 />
<field_8 />
<field_9 />
</Graphic>
<Graphic>
<object_type>LINE</object_type>
<field_1>10.824742317199707</field_1>
<field_2>562.8865966796875</field_2>
<field_3>3.6082475185394287</field_3>
<field_4>541.23712158203125</field_4>
<field_6 />
<field_7 />
<field_8 />
<field_9 />
</Graphic>
after reading the xml file i am iterating through the coordinates. and drawing the object on the html5 canvas.
I have two troubles....
1) the photo is being drawn upside down... so i need to rotate the canvas
Image can be viewed here
2) i need to scale the whole object within the canvas. for now i am dividing every coordinate with 8 to scale it down. how i can scale it according to screen resolution and canvas...
cannot get my head around this
If you are able to get the object width and height, you just need to calculate the scale factor related to the canvas:
var scaleFactorW = canvas.width/obj.width,
scaleFactorH = canvas.height/obj.height;
context.scale(scaleFactorW , scaleFactorH);
startDrawing(obj);
See this DEMO at jsfiddle.net
EDIT:
To maintain the object proportions for different canvas resolutions we need to calculate a scale factor that verifies the max scale based on canvas aspect ratio and the object proportions.
var canvasAspectRatio = canvas.width / canvas.height;
var objAspectRatio = obj.width / obj.height;
var scaleFactor = 1;
if (canvasAspectRatio > objAspectRatio) {
scaleFactor = canvas.height / obj.height;
} else {
scaleFactor = canvas.width / obj.width;
}
context.scale(scaleFactor, scaleFactor);
startDrawing(obj)
Found answer to the first question after doing bit of maths...
my canvas was
<canvas id="myCanvas" width="800" height="500" style="background: #FFFFFF; border: 5px solid black;" role="img">
Your browser does not support the canvas element.
</canvas>
and javascript became...
startDrawing(obj);
// rotate 180 degrees clockwise
context.rotate(180*(Math.PI/180));
// translate context to opposite of your actual canvas
context.translate(-800, -500);
still need the answer for the 2nd question.... the scaling

HTML5 canvas, scale image after drawing it

I'm trying to scale an image that has already been draw into canvas.
This is the code:
var canvas = document.getElementById('splash-container');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
// draw image at its original size
context.drawImage(imageObj, 0, 0);
};
imageObj.src = 'images/mine.jpeg';
// Now let's scale the image.
// something like...
imageObj.scale(0.3, 0.3);
How should I do?
You're thinking about it wrong. Once you've drawn the image onto the canvas it has no relationship to the imageObj object. Nothing you do to imageObj will affect what's already drawn. If you want to scale the image, do in the drawImage function:
drawImage(imgObj, 0, 0, imgObj.width * 0.3, imgObj.height * 0.3)
If you want to animate the scaling or are looking to achieve some other effect which requires you to draw the image at full size initially you'll have to first clear it before drawing the scaled down image.
What robertc says is correct, but if you really wanted to scale an image on a canvas after drawing it for some reason, you could just scale the whole canvas using the CSS width/height properties and that would scale the image without having to redraw it.

Resources