I am creating heat maps in Windows store apps 8.1 using algorithm provided in stack overflow.
first approach:
public Color HeatMapColor(decimal value, decimal min, decimal max)
{
decimal val = (value - min) / (max - min);
int r = Convert.ToByte(255 * val);
int g = Convert.ToByte(255 * (1 - val));
int b = 0;
return Color.FromArgb(255,r,g,b);
}
second approach:
public Brush getColourTemp(int maxVal,int minVal ,double actual )
{
int maxVal = 70000000;
int minVal = 100000;
var midVal = (maxVal - minVal) / 2;
int intR;
int intG;
int intB = Convert.ToInt32(Math.Round(0.0));
if (actual >= midVal)
{
intR = 255;
intG = Convert.ToInt32(Math.Round(255 * ((maxVal - actual) / (maxVal - midVal))));
}
else
{
intG = 255;
intR = Convert.ToInt32(Math.Round(255 * ((actual) - minVal) / (midVal - minVal)));
}
// Color background = Color.FromArgb(255, (byte)ran.Next(255), (byte)ran.Next(255), (byte)ran.Next(255));
Color background = Color.FromArgb(255, (byte)intR, (byte)intG, (byte)intB);
return new SolidColorBrush(background);
//byte[] bytes = BitConverter.GetBytes(actual);
//return new SolidColorBrush(Color.FromArgb(bytes[0], bytes[1], bytes[2], bytes[3]));
// return to_rgb(intR, intG, intB);
}
But in both the case blue colour is zero why. I need blue color in heat map also can any one help me out.
I am creating heat map using Winrt xaml toolkit line graphs
code details
for (int i = 0; i <= 200; i++)
{`enter code here`
if (i > 25)
{
LineChart.Series.RemoveAt(0);
}
List<FinancialStuff> financialStuffList = new List<FinancialStuff>();
LineSeries line = new LineSeries();
line.Title = "";
line.IndependentValuePath = "Name";
line.DependentValuePath = "Amount";
for (int j = 0; j < 256; j++)
{
financialStuffList.Add(new FinancialStuff() { Name = i, Amount = j - 130, FavoriteColor = ConvertTotalToRgb(i, j) });
}
line.ItemsSource = financialStuffList;
line.DataPointStyle = style;
LineChart.Series.Add(line);
if (i >= 25)
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
//******************************************************************************
public Brush ConvertTotalToRgb(int val, int val1)
{`enter code here`
double actual = 0.0;
int range = 70000000 - 100000;
actual = data[val, val1];
int main = Convert.ToInt32(255 * actual / range);
string hexR = main.ToString("X2");
int flip = Convert.ToInt32(255 * (1 - (actual / range)));
string hexB = flip.ToString("X2");
string colorValue = "#" + hexR + "00" + hexB;
byte R = Convert.ToByte(colorValue.Substring(1, 2), 16);
byte G = Convert.ToByte(colorValue.Substring(3, 2), 16);
byte B = Convert.ToByte(colorValue.Substring(5, 2), 16);
Color background = Color.FromArgb((byte)255, R, G, B);
return new SolidColorBrush(background);
}
}
very bad performance after i=50 it is very slow and not loading may be performance issue of in line graphs as it is huge number.
Please help if any body can tell improvement or suggests other ways to create Spectrogram in windows store apps 8.1 development.
XAML page
<Page xmlns:Charting="using:WinRTXamlToolkit.Controls.DataVisualization.Charting"
x:Class="MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Spect"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid >
<Grid.Resources>
<Style
x:Key="ColorByPreferenceColumn"
x:Name="abc"
TargetType="Charting:LineDataPoint">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate
TargetType="Charting:LineDataPoint">
<Grid Background="{Binding FavoriteColor}">
<Polygon>
<Polygon.Fill>
<LinearGradientBrush>
<GradientStop Color="#77ffffff" Offset="0"/>
<GradientStop Color="#00ffffff" Offset="1"/>
</LinearGradientBrush>
</Polygon.Fill>
</Polygon>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Charting:Chart x:Name="LineChart" HorizontalAlignment="Left" VerticalAlignment="Top" Width="300" Height="600" Margin="208,107,0,0">
</Charting:Chart>
<Button Content="Data" HorizontalAlignment="Left" Margin="175,31,0,0" VerticalAlignment="Top" Click="Button_Click"/>
</Grid>
Related
A game I am currently developing uses a 5x5 matrix to change the colors of the image on a per pixel basis. I was wondering if anyone has developed an extremely fast algorithm for something like this.
For every Pixel(setPixel(sourcePixel * Matrix))
I have built my own algorithm for this by getting and setting pixels on pixmap then drawing a new pixmap from this through iterating every pixel with set/get pixel. I have found a reasonably fast algorithm for this (150 million pixels ~3 seconds), but I was thinking of another idea rather than using the pixmap but I am unsure of how to implement this. Libgdx provides a FileHandle.readBytes() method that reads image files (in my case PNG) to byte arrays. My thought was rather than creating a pixmap, read the byte array while iterating the pixels. While iterating I would be drawing a new pixmap meaning their really is no point for me to make one for the base pixmap in the first place. With tests I found that with my current algorithm, 70% of the time it takes is from the method (PixMap.getPixel(x, y), and I could bypass this by straight reading the byte array. I have looked into PNG readers for byte array's online but to no avail.
Note I am unable to use ImageIO due it being an android based game. Would it make it faster by reading the byte array data while iterating/ is it possible to do this?
In the code below, JList is basically a HashMap in this context
private static JList<Integer, Pixmap> colorShiftImage(Pixmap p, JList<Integer, float[][]> cms){
JList<float[][], Pixmap> tempList = new JList<>();
for(int i = cms.size() - 1; i > -1; --i){
tempList.add(cms.getInt(i), new Pixmap(p.getWidth(), p.getHeight(), Pixmap.Format.RGBA8888));
}
for(int y = p.getHeight() - 1; y > -1; --y){
for(int x = p.getWidth() - 1; x > -1; --x){
int v = p.getPixel(x, y);
if(v != 0) {
r = ((v & 0xff000000) >>> 24);
g = ((v & 0x00ff0000) >>> 16);
b = ((v & 0x0000ff00) >>> 8);
a = ((v & 0x000000ff));
for(int i = tempList.size() - 1; i > -1; --i) {
float[][] c = tempList.getIDList().get(i);
tempList.getInt(i).drawPixel(x, y, (((l((r * c[0][0]) + (c[1][0] * g) + (c[2][0] * b) + (c[3][0] * a) + c[4][0])) << 24)
| ((l((r * c[0][1]) + (c[1][1] * g) + (c[2][1] * b) + (c[3][1] * a) + c[4][1])) << 16)
| ((l((r * c[0][2]) + (c[1][2] * g) + (c[2][2] * b) + (c[3][2] * a) + c[4][2])) << 8)
| ((l((r * c[0][3]) + (c[1][3] * g) + (c[2][3] * b) + (c[3][3] * a) + c[4][3])))));
}
}
}
}
JList<Integer, Pixmap> returnL = new JList<>();
for(int i = tempList.size() - 1; i > - 1; --i){
returnL.add(cms.getIDList().get(i), tempList.getInt(i));
}
return returnL;
}
public static int l(float v){
if(v < 0)return 0;
else if(v > 255)return 255;
return (int) v;
}
I want to capture screen in libGdx . I use this code for my problem. On Desktop it work . But when I run on my android , I can't find image capture screen. How can I fix it? Thanks for reading my question.
public class ScreenshotFactory {
private static int counter = 1;
public static void saveScreenshot() {
try {
FileHandle fh;
do {
if (Gdx.app.getType() == ApplicationType.Desktop)
Infor.linkScreenShot = "D://chupngoc" + counter + ".png";
else
Infor.linkScreenShot = Gdx.files.getExternalStoragePath()
+ counter + ".png";
Infor.nameImage = counter + ".png";
fh = new FileHandle(Infor.linkScreenShot);
counter++;
} while (fh.exists());
Pixmap pixmap = getScreenshot(0, 0, Gdx.graphics.getWidth(),
Gdx.graphics.getHeight(), true);
PixmapIO.writePNG(fh, pixmap);
pixmap.dispose();
} catch (Exception e) {
}
}
private static Pixmap getScreenshot(int x, int y, int w, int h,
boolean yDown) {
Gdx.gl.glPixelStorei(GL20.GL_PACK_ALIGNMENT, 1);
final Pixmap pixmap1 = new Pixmap(w, h, Format.RGBA8888);
ByteBuffer pixels1 = pixmap1.getPixels();
Gdx.gl.glReadPixels(x, y, w, h, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE,
pixels1);
Pixmap pixmap = pixmap1;
if (yDown) {
// Flip the pixmap upside down
ByteBuffer pixels = pixmap.getPixels();
int numBytes = w * h * 4;
byte[] lines = new byte[numBytes];
int numBytesPerLine = w * 4;
for (int i = 0; i < h; i++) {
pixels.position((h - i - 1) * numBytesPerLine);
pixels.get(lines, i * numBytesPerLine, numBytesPerLine);
}
pixels.clear();
pixels.put(lines);
}
return pixmap;
}
}
Your problem lies here...
fh = new FileHandle(Infor.linkScreenShot);
This way of creating a FileHandle is for the desktop only and will not work on Android.
You should create a file using Gdx.files.external instead...
fh = Gdx.files.external(Infor.linkScreenShot);
A couple of weeks ago I implemented this method https://github.com/libgdx/libgdx/wiki/Take-a-Screenshot
And it worked great with libgdx 1.3.1 . Now though I upgraded to 1.6.0 and it have stopped working.
When the method is executed it freezes. I have it implemented on a button, and it gets stuck in "downclick" and nothing more happens.
private void saveScreenshot() {
try{
FileHandle fh;
do{
fh = new FileHandle(files.getLocalStoragePath() + "screenshot" + ".png");
}while(fh.exists());
Pixmap pixmap = getScreenshot(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight() - 130, true);
PixmapIO.writePNG(fh, pixmap);
pixmap.dispose();
System.out.println("Path:" + fh.toString());
}catch(Exception e) {
}
}
private Pixmap getScreenshot(int x, int y, int w, int h, boolean yDown){
final Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(x, y, w, h);
w = pixmap.getWidth();
h = pixmap.getHeight();
if(yDown) {
ByteBuffer pixels = pixmap.getPixels();
int numBytes = w * h * 4;
byte[] lines = new byte[numBytes];
int numBytesPerLine = w * 4;
for (int i = 0; i < h; i++) {
pixels.position((h - i - 1) * numBytesPerLine);
pixels.get(lines, i * numBytesPerLine, numBytesPerLine);
}
pixels.clear();
pixels.put(lines);
}
return pixmap;
}
btnArrow.addListener(new ChangeListener() {
//photoshop "save" and "back" on arrow/back image to clarify.
#Override
public void changed(ChangeEvent event, Actor actor) {
saveScreenshot();
sharePhoto();
}
});
I share the image to facebook aswell. And this method is in AndroidLauncher of course and is passed through an interface. And here I fetch the screenshot:
public void sharePhoto() {
Matrix matrix = new Matrix();
String filePath = (files.getLocalStoragePath() + "screenshot" + ".png");
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
Bitmap rotateBit = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//Starts sharing process
SharePhoto photo = new SharePhoto.Builder()
.setBitmap(rotateBit)
.build();
SharePhotoContent content = new SharePhotoContent.Builder()
.addPhoto(photo)
.build();
share.show(content);
}
So what I believe may be the issue is libgdx have done changes on Pixmap class or Bitmap class of some sort. Since sharing a link through facebook on that button works fine.
I also printed the path as you can see in saveScreenshot() and it returns this
selinux_android_setcategory: no category for userid: 0, path: /data/data/com.sparc.tormt.android/lib
Is it stuck because this is an infinite loop if the file already exists:
do {
fh = new FileHandle(files.getLocalStoragePath() + "screenshot" + ".png");
} while(fh.exists());
UPDATE: Once I got this demo working... holy smokes, it's SLOW, like 12-16 seconds for only a level 2 render (when image is around 1000x2000 pixels). This is not even worth bothering with.
I found this really awesome and hopeful looking code in the top answer here: Resizing an image in an HTML5 canvas
//returns a function that calculates lanczos weight
function lanczosCreate(lobes){
return function(x){
if (x > lobes)
return 0;
x *= Math.PI;
if (Math.abs(x) < 1e-16)
return 1
var xx = x / lobes;
return Math.sin(x) * Math.sin(xx) / x / xx;
}
}
//elem: canvas element, img: image element, sx: scaled width, lobes: kernel radius
function thumbnailer(elem, img, sx, lobes){
this.canvas = elem;
elem.width = img.width;
elem.height = img.height;
elem.style.display = "none";
this.ctx = elem.getContext("2d");
this.ctx.drawImage(img, 0, 0);
this.img = img;
this.src = this.ctx.getImageData(0, 0, img.width, img.height);
this.dest = {
width: sx,
height: Math.round(img.height * sx / img.width),
};
this.dest.data = new Array(this.dest.width * this.dest.height * 3);
this.lanczos = lanczosCreate(lobes);
this.ratio = img.width / sx;
this.rcp_ratio = 2 / this.ratio;
this.range2 = Math.ceil(this.ratio * lobes / 2);
this.cacheLanc = {};
this.center = {};
this.icenter = {};
setTimeout(this.process1, 0, this, 0);
}
thumbnailer.prototype.process1 = function(self, u){
self.center.x = (u + 0.5) * self.ratio;
self.icenter.x = Math.floor(self.center.x);
for (var v = 0; v < self.dest.height; v++) {
self.center.y = (v + 0.5) * self.ratio;
self.icenter.y = Math.floor(self.center.y);
var a, r, g, b;
a = r = g = b = 0;
for (var i = self.icenter.x - self.range2; i <= self.icenter.x + self.range2; i++) {
if (i < 0 || i >= self.src.width)
continue;
var f_x = Math.floor(1000 * Math.abs(i - self.center.x));
if (!self.cacheLanc[f_x])
self.cacheLanc[f_x] = {};
for (var j = self.icenter.y - self.range2; j <= self.icenter.y + self.range2; j++) {
if (j < 0 || j >= self.src.height)
continue;
var f_y = Math.floor(1000 * Math.abs(j - self.center.y));
if (self.cacheLanc[f_x][f_y] == undefined)
self.cacheLanc[f_x][f_y] = self.lanczos(Math.sqrt(Math.pow(f_x * self.rcp_ratio, 2) + Math.pow(f_y * self.rcp_ratio, 2)) / 1000);
weight = self.cacheLanc[f_x][f_y];
if (weight > 0) {
var idx = (j * self.src.width + i) * 4;
a += weight;
r += weight * self.src.data[idx];
g += weight * self.src.data[idx + 1];
b += weight * self.src.data[idx + 2];
}
}
}
var idx = (v * self.dest.width + u) * 3;
self.dest.data[idx] = r / a;
self.dest.data[idx + 1] = g / a;
self.dest.data[idx + 2] = b / a;
}
if (++u < self.dest.width)
setTimeout(self.process1, 0, self, u);
else
setTimeout(self.process2, 0, self);
};
thumbnailer.prototype.process2 = function(self){
self.canvas.width = self.dest.width;
self.canvas.height = self.dest.height;
self.ctx.drawImage(self.img, 0, 0);
self.src = self.ctx.getImageData(0, 0, self.dest.width, self.dest.height);
var idx, idx2;
for (var i = 0; i < self.dest.width; i++) {
for (var j = 0; j < self.dest.height; j++) {
idx = (j * self.dest.width + i) * 3;
idx2 = (j * self.dest.width + i) * 4;
self.src.data[idx2] = self.dest.data[idx];
self.src.data[idx2 + 1] = self.dest.data[idx + 1];
self.src.data[idx2 + 2] = self.dest.data[idx + 2];
}
}
self.ctx.putImageData(self.src, 0, 0);
self.canvas.style.display = "block";
}
...
img.onload = function() {
var canvas = document.createElement("canvas");
new thumbnailer(canvas, img, 188, 3); //this produces lanczos3
//but feel free to raise it up to 8. Your client will appreciate
//that the program makes full use of his machine.
document.body.appendChild(canvas);
}
However, this implementation loads an image and renders it, end of story.
I have been trying to re-implement this code so that it does the filtering every time an existing canvas is scaled (think, zooming in and out of an image or document) without having to load a new image or create a new canvas.
How can I adapt it to work this way? Or is that even possible?
What you want to do is something like a singleton to reuse your canvas object. This will let you save the cost of create a new canvas object each time and you will reuse the same object
function getCanvas(){
var canvas;
if (typeof canvas === "undefined"){ canvas = document.createElement("canvas");}
return canvas;
}
img.onload = function() {
var canvas = getCanvas("canvas");
.... THE REST OF YOUR CODE .......
}
.
However this is not what slows your code, image scaling Algorithms are really heavy algorithms with intensive cpu use "usually make use of gpu acceleration at a really low level", and use advanced techniques like multiple bufferr and so others. here is a interesting tutorial in java.net on how image scaling works, it is in java but you can interpolate to any language.
Javascript is not ready for this techniques, so I recommend you to use the transformations available in the canvas api, as in the tutorial you read the efficient way is using the canvas2Dcontext.
var ctx = canvas.getContext("2d");
ctx.scale(2,2);
I have a Silverlight grid with a bunch of content in it (rectangles, textBlocks, etc.) which represents content in a room. Because it gets pretty complex, I decided I needed an ability to "zoom-in" on the grid. I found some good code to do that, but the problem is that after zooming the grids associated ScrollViewer doesn't scroll the full distance down or to the right. How can I force it to update so that I can scroll to the bottom and all the way to the right?
If it helps, here's the code to permit zooming of my Grid:
var style = new Style(typeof(Grid));
var scale = new ScaleTransform();
scale.CenterX = .5;
scale.CenterY =.5;
scale.ScaleX = Scale;
scale.ScaleY = Scale;
var rs = new Setter();
rs.Property = DataGridCell.RenderTransformProperty;
rs.Value = scale;
style.Setters.Add(rs);
OtdrPatchLocationGrid.Style = style;
and here is the XAML that shows the grid and the scroll viewer
<ScrollViewer Name="scViewer" Grid.Row="1" Visibility="Visible" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
<Grid x:Name="OtdrPatchLocationGrid" MinHeight="350" VerticalAlignment="Stretch" Background="Yellow" Grid.Row="1" Grid.Column="0" Margin="0" MouseDown="OtdrRackViewer_MouseDown">
</Grid>
</ScrollViewer>
I'm working on the same issue now,
the ScrollViewer is affected only by the change in Width or Height,
so to fix the problem, you have to do as the following:
suppose we got the Grid or Canvas named (ZoomCanvas)
in the code behind:
double initialCanvasHeight;
double initialCanvasWidth;
public void MainPage() //As the Constructor
{
initialCanvasHeight = ZoomCanvas.Height;
initialCanvasWidth = ZoomCanvas.Width;
}
ZoomCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
/*Assuming you have the scaling code here and the object CanvasScale is used to scale the canvas*/
foreach (var node in ZoomCanvas)
{
var nodeTop = Canvas.GetTop(node);
var nodeLeft = Canvas.GetLeft(node);
if(mostTopValue < nodeTop)
mostTopValue = nodeTop;
if(mostLeftValue < nodeLeft)
mostLeftValue = nodeLeft;
var desiredHeight = (mostTopValue + NodeHeight)*canvasScale.ScaleY;
var desiredWidth = (mostLeftValue + NodeWidth) * canvasScale.ScaleX;
if (desiredHeight > canvasInitialHeight)
{
while (heightToIncrease < desiredHeight)
heightToIncrease += 10;
ZoomCanvas.Height = heightToIncrease;
}
else
while (ZoomCanvas.Height > canvasInitialHeight)
ZoomCanvas.Height -= 10;
if (desiredWidth > canvasInitialWidth)
{
while (widthToIncrease < desiredWidth)
widthToIncrease += 10;
ZoomCanvas.Width = widthToIncrease;
}
else while (ZoomCanvas.Height > canvasInitialHeight)
ZoomCanvas.Width -= 10;
}
scrollViewer.UpdateLayout();
}