Capture everything inside a rect in unity - c#

I have a rect, which has inside of it a portion of my UI, I want to take a 'screenshot' of everything inside of that rect and put it into a .jpeg file.
I have absolutely no idea how I can do this, and if it's even possible. Unfortunately, I couldn't find anything on the internet.

What you need to do is use a RenderTexture
Create a RenderTexture Unity Object in the editor
Create a Camera that sees exactly what you want in your screenshot.
Cameras in Unity have an option called Target Texture. Put your RenderTexture in this field. The result is that the camera will render in this texture instead of on the screen. See the Manual for detailed examples.
Make a script that has access to your RenderTexture Object. This script create a Texture2D using Texture2D.ReadPixels. This allows to create a Texture2D object from the texture.
Use Texture2D.EncodeToJpg to save your Texture2D in a file

You need this:
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class TakeScreenshotAndSave : MonoBehaviour
{
//Object To Screenshot
[SerializeField] private RectTransform _objToScreenshot;
//Assign the button to take screenshot on clicking
[SerializeField] private Button _takeScreenshotButton;
void Start()
{
_takeScreenshotButton.onClick.AddListener(OnClickTakeScreenshotAndSaveButton);
}
private void OnClickTakeScreenshotAndSaveButton()
{
StartCoroutine(TakeSnapShotAndSave());
}
//Using a Coroutine instead of normal method
public IEnumerator TakeSnapShotAndSave()
{
//Code will throw error at runtime if this is removed
yield return new WaitForEndOfFrame();
//Get the corners of RectTransform rect and store it in a array vector
Vector3[] corners = new Vector3[4];
_objToScreenshot.GetWorldCorners(corners);
//Remove 100 and you will get error
int width = ((int)corners[3].x - (int)corners[0].x) - 100;
int height = (int)corners[1].y - (int)corners[0].y;
var startX = corners[0].x;
var startY = corners[0].y;
//Make a temporary texture and read pixels from it
Texture2D ss = new Texture2D(width, height, TextureFormat.RGB24, false);
ss.ReadPixels(new Rect(startX, startY, width, height), 0, 0);
ss.Apply();
Debug.Log("Start X : " + startX + " Start Y : " + startY);
Debug.Log("Screen Width : " + Screen.width + " Screen Height : " +
Screen.height);
Debug.Log("Texture Width : " + width + " Texture Height : " + height);
//Save the screenshot to disk
byte[] byteArray = ss.EncodeToPNG();
string savePath = Application.persistentDataPath + "/ScreenshotSave.png";
System.IO.File.WriteAllBytes(savePath, byteArray);
Debug.Log("Screenshot Path : " + savePath);
// Destroy texture to avoid memory leaks
Destroy(ss);
}
}

Related

Vuforia - Unity low image quality

I am using Vuforia with Unity for an Android AR app. I made it to take a screenshot of a specific area of the screen with the click of a button. It reads pixels in that specific area when the button is clicked.
The problem is, the resulting image is blurry/ low resolution. How can I increase the quality of the image?
I tried changing "Camera Device Mode" to "MODE_OPTIMIZE_QUALITY" and increasing "Number Divisions" in "Video Background" setting. But nothing happens. I also tried removing ARCore and changing "ARCore Requirement" to "DONT_USE" mode.
This is the code to take a snapshot :
yield return new WaitForEndOfFrame();
//Get the corners of RectTransform rect and store it in a array vector
Vector3[] corners = new Vector3[4];
_objToScreenshot.GetWorldCorners(corners);
//Remove 100 and you will get error
int width = ((int)corners[3].x - (int)corners[0].x) - 100;
int height = (int)corners[1].y - (int)corners[0].y;
var startX = corners[0].x;
var startY = corners[0].y;
//Make a temporary texture and read pixels from it
Texture2D ss = new Texture2D(width, height, TextureFormat.RGB24, false);
ss.ReadPixels(new Rect(startX, startY, width, height), 0, 0);
ss.Apply();
//Save the screenshot to disk
byte[] byteArray = ss.EncodeToPNG();
string savePath = Application.persistentDataPath + "/" + System.DateTime.Now.ToString("HH-mm-ss dd,MM, yyyy") + ".png";
System.IO.File.WriteAllBytes(savePath, byteArray);
//Debug.Log("Screenshot Path : " + savePath);
// Destroy texture to avoid memory leaks
Destroy(ss);

How to take Screen Shot in Particular Area in unity

I'm using Unity 2018. In my project i have to take particular area screen. I have using the below code. It is working. But The exact image is not working. It goes some extent. How can i take the exact image.
using UnityEngine;
using System.Collections;
using System;
public class ScreenCapture : MonoBehaviour
{
public RenderTexture overviewTexture;
GameObject OVcamera;
public string path = "";
void Start()
{
OVcamera = GameObject.FindGameObjectWithTag("OverviewCamera");
}
void LateUpdate()
{
if (Input.GetKeyDown("f9"))
{
StartCoroutine(TakeScreenShot());
}
}
// return file name
string fileName(int width, int height)
{
return string.Format("screen_{0}x{1}_{2}.png",
width, height,
System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
}
public IEnumerator TakeScreenShot()
{
yield return new WaitForEndOfFrame();
Camera camOV = OVcamera.camera;
RenderTexture currentRT = RenderTexture.active;
RenderTexture.active = camOV.targetTexture;
camOV.Render();
Texture2D imageOverview = new Texture2D(camOV.targetTexture.width, camOV.targetTexture.height,
TextureFormat.RGB24, false);
imageOverview.ReadPixels(new Rect(0, 0, camOV.targetTexture.width, camOV.targetTexture.height), 0,
0);
imageOverview.Apply();
RenderTexture.active = currentRT;
byte[] bytes = imageOverview.EncodeToPNG();
// save in memory
string filename = fileName(Convert.ToInt32(imageOverview.width),
Convert.ToInt32(imageOverview.height));
path = Application.persistentDataPath + "/Snapshots/" + filename;
System.IO.File.WriteAllBytes(path, bytes);
}
}
this is my above code..
use this:
Texture2D screencap;
Texture2D border;
bool shot=false;
public string path;
void Start () {
screencap=new Texture2D(300,200,TextureFormat.RGB24,false);
border=new Texture2D(2,2,TextureFormat.ARGB32,false);
border.Apply();
}
// Update is called once per frame
void Update () {
if(Input.GetKeyUp(KeyCode.Mouse0))
{
StartCoroutine("Capture");
}
}
string fileName(int width, int height)
{
return string.Format("screen_{0}x{1}_{2}.png",
width, height,
System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
}
void OnGUI()
{
GUI.DrawTexture(new Rect(200,100,300,2),border,ScaleMode.StretchToFill);
GUI.DrawTexture(new Rect(200,300,300,2),border,ScaleMode.StretchToFill);
GUI.DrawTexture(new Rect(195,100,2,200),border,ScaleMode.StretchToFill);
GUI.DrawTexture(new Rect(500,100,2,201),border,ScaleMode.StretchToFill);
if(shot)
{
GUI.DrawTexture(new Rect(50,10,60,40),screencap,ScaleMode.StretchToFill);
//Application.CaptureScreenshot(myFolderLocation+myFilename);
}
}
IEnumerator Capture()
{
yield return new WaitForEndOfFrame();
screencap.ReadPixels(new Rect(198,98,298,198),0,0);
screencap.Apply();
shot=true;
byte[] bytes=border.EncodeToPNG();
string filename=fileName(Convert.ToInt32(screencap.width), Convert.ToInt32(screencap.height));
Application.CaptureScreenshot("D:"+filename);
}
This script takes customised screeenshot of any Object that has RectTransform component attached to it.
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class TakeScreenshotAndSave : MonoBehaviour
{
//Object To Screenshot
[SerializeField] private RectTransform _objToScreenshot;
//Assign the button to take screenshot on clicking
[SerializeField] private Button _takeScreenshotButton;
void Start()
{
_takeScreenshotButton.onClick.AddListener(OnClickTakeScreenshotAndSaveButton);
}
private void OnClickTakeScreenshotAndSaveButton()
{
StartCoroutine(TakeSnapShotAndSave());
}
//Using a Coroutine instead of normal method
public IEnumerator TakeSnapShotAndSave()
{
//Code will throw error at runtime if this is removed
yield return new WaitForEndOfFrame();
//Get the corners of RectTransform rect and store it in a array vector
Vector3[] corners = new Vector3[4];
_objToScreenshot.GetWorldCorners(corners);
//Remove 100 and you will get error
int width = ((int)corners[3].x - (int)corners[0].x) - 100;
int height = (int)corners[1].y - (int)corners[0].y;
var startX = corners[0].x;
var startY = corners[0].y;
//Make a temporary texture and read pixels from it
Texture2D ss = new Texture2D(width, height, TextureFormat.RGB24, false);
ss.ReadPixels(new Rect(startX, startY, width, height), 0, 0);
ss.Apply();
Debug.Log("Start X : " + startX + " Start Y : " + startY);
Debug.Log("Screen Width : " + Screen.width + " Screen Height : " +
Screen.height);
Debug.Log("Texture Width : " + width + " Texture Height : " + height);
//Save the screenshot to disk
byte[] byteArray = ss.EncodeToPNG();
string savePath = Application.persistentDataPath + "/ScreenshotSave.png";
System.IO.File.WriteAllBytes(savePath, byteArray);
Debug.Log("Screenshot Path : " + savePath);
// Destroy texture to avoid memory leaks
Destroy(ss);
}
}

How to create 2D map in unity using single image?

I have to create 2D map in unity using single image. So, i have one .png file with 5 different pieces out of which I have to create a map & i am not allowed to crop the image. So, how do create this map using only one image.
I am bit new to unity, i tried searching but didn't find exactly what i am looking for. Also tried, tilemap using Pallet but couldn't figure out how to extract only one portion of the image.
You can create various Sprites from the given texture on the fly in code.
You can define which part of a given Texture2D shall be used for the Sprite using Sprite.Create providing the rect in pixel coordinates of the given image. Remember however that in unity texture coordinates start bottom left.
Example use the given pixel coordinate snippet of a texture for the attached UI.Image component:
[RequireComponent(typeof(Image))]
public class Example : MonoBehaviour
{
// your texture e.g. from a public field via the inspector
public Texture2D texture;
// define which pixel coordinates to use for this sprite also via the inspector
public Rect pixelCoordinates;
private void Start()
{
var newSprite = Sprite.Create(texture, pixelCoordinates, Vector2.one / 2f);
GetComponent<Image>().sprite = newSprite;
}
// called everytime something is changed in the Inspector
private void OnValidate()
{
if (!texture)
{
pixelCoordinates = new Rect();
return;
}
// reset to valid rect values
pixelCoordinates.x = Mathf.Clamp(pixelCoordinates.x, 0, texture.width);
pixelCoordinates.y = Mathf.Clamp(pixelCoordinates.y, 0, texture.height);
pixelCoordinates.width = Mathf.Clamp(pixelCoordinates.width, 0, pixelCoordinates.x + texture.width);
pixelCoordinates.height = Mathf.Clamp(pixelCoordinates.height, 0, pixelCoordinates.y + texture.height);
}
}
Or you get make a kind of manager class for generating all needed sprites once e.g. in a list like
public class Example : MonoBehaviour
{
// your texture e.g. from a public field via the inspector
public Texture2D texture;
// define which pixel coordinates to use for this sprite also via the inspector
public List<Rect> pixelCoordinates = new List<Rect>();
// OUTPUT
public List<Sprite> resultSprites = new List<Sprite>();
private void Start()
{
foreach(var coordinates in pixelCoordinates)
{
var newSprite = Sprite.Create(texture, coordinates, Vector2.one / 2f);
resultSprites.Add(newSprite);
}
}
// called everytime something is changed in the Inspector
private void OnValidate()
{
if (!texture)
{
for(var i = 0; i < pixelCoordinates.Count; i++)
{
pixelCoordinates[i] = new Rect();
}
return;
}
for (var i = 0; i < pixelCoordinates.Count; i++)
{
// reset to valid rect values
var rect = pixelCoordinates[i];
rect.x = Mathf.Clamp(pixelCoordinates[i].x, 0, texture.width);
rect.y = Mathf.Clamp(pixelCoordinates[i].y, 0, texture.height);
rect.width = Mathf.Clamp(pixelCoordinates[i].width, 0, pixelCoordinates[i].x + texture.width);
rect.height = Mathf.Clamp(pixelCoordinates[i].height, 0, pixelCoordinates[i].y + texture.height);
pixelCoordinates[i] = rect;
}
}
}
Example:
I have 4 Image instances and configured them so the pixelCoordinates are:
imageBottomLeft: X=0, Y=0, W=100, H=100
imageTopLeft: X=0, Y=100, W=100, H=100
imageBottomRight: X=100, Y=0, W=100, H=100
imageTopRight: X=100, Y=100, W=100, H=100
The texture I used is 386 x 395 so I'm not using all of it here (just added the frames the Sprites are going to use)
so when hitting Play the following sprites are created:

LoadRawTextureData() not enough data provided error in Unity

I am working on a project using ARcore.
I need a real world screen that is visible on the ARcore camera, formerly using the method of erasing UI and capturing.
But it was so slow that I found Frame.CameraImage.Texture in Arcore API
It worked normally in a Unity Editor environment.
But if you build it on your phone and check it out, Texture is null.
Texture2D snap = (Texture2D)Frame.CameraImage.Texture;
What is the reason? maybe CPU problem?
and I tried to do a different function.
public class TestFrameCamera : MonoBehaviour
{
private Texture2D _texture;
private TextureFormat _format = TextureFormat.RGBA32;
// Use this for initialization
void Start()
{
_texture = new Texture2D(Screen.width, Screen.height, _format, false, false);
}
// Update is called once per frame
void Update()
{
using (var image = Frame.CameraImage.AcquireCameraImageBytes())
{
if (!image.IsAvailable) return;
int size = image.Width * image.Height;
byte[] yBuff = new byte[size];
System.Runtime.InteropServices.Marshal.Copy(image.Y, yBuff, 0, size);
_texture.LoadRawTextureData(yBuff);
_texture.Apply();
this.GetComponent<RawImage>().texture = _texture;
}
}
}
But if I change the texture format, it will come out.
private TextureFormat _format = TextureFormat.R8;
it is work, but i don't want to red color image, i want to rgb color
what i should do?
R8 Just red data.
You can use TextureFormat.RGBA32, and set buffer like this:
IntPtr _buff = Marshal.AllocHGlobal(width * height*4);

How to write data to .bmp file using an external program from unity?

I'm adding a feature to a project that will allow users to see a heat map representation of their mouse movements on the screen in real time. My goal is to make this API as dynamic as possible.
By dynamic, I mean I would like users to be able to use this API to generate the heat map in real time and then plug that heat map into their third party graphics software to view that heat map. (i.e Unity, React, Mobile, etc.. )
For testing purposes the third party graphics software that I am using is Unity.
I have created a .cs unity script that does the following per frame:
Start recording mouse locations.
Have ExternalProgram.exe generate a bitmap image using the
points that unity just recorded.
Then have Unity display the updated .bmp image on the screen.
Right now the problem that I am having is that the .bmp file is not being created when I use ProcessStartInfo in my unity script to run the .exe that is in charge of creating the .bmp image.
I've been debugging this code for the past week trying to figure out what is wrong with it. I know for a fact that Unity is successfully recording the mouse's location and passing those values to the .exe after calling ProcessStartInfo.
But for some reason it doesn't actually create the .bmp file. This is weird because if I independently run the ExternalProject in Visual Studio then it works just fine and it creates the .bmp file and shows the correct heat map representation on the image.
I figured that maybe starting a program and passing it tons of data and having that program create a file would be a lot of work for unity to do every single frame. (I am open to suggestions on ways to get around having to do that)
So I decided to just have the script record points for the first 15 seconds and then try to write that data to the .bmp file but that didn't work either.
Main program file for ExternalProject.exe
class Program
{
public static void Main(string[] args)
{
string arguments = "";
foreach (string arg in args)
{
arguments += arg;
}
Console.WriteLine("My Args: " + arguments + "--EOF");
bool noArguments = String.IsNullOrEmpty(arguments);
if (noArguments)
{
// Test input data
arguments = "(111,222)|(333,444)|(555,777)|(888,999)|(1000,1000)|(1000,1000)|(1000,1000)";
}
// The method ConvertStringToSignalsList() has already been tested and it works.
List<MouseMovementSignal> signals = ConvertStringToSignalsList(arguments);
CreateMouseHeatmap(signals);
Console.WriteLine("Press Enter to close...");
Console.ReadLine();
}
private static void CreateMouseHeatmap(List<MouseMovementSignal> argumentSignals)
{
int Height = 2100;
int Width = 3800;
List<MouseMovementSignal> mouseSignals
= argumentSignals; // Program perameters
//= getRecordedMouseData(); // DB
//= createFakeMouseSignals(Height, Width); // Generates fake signals
try
{
HeatmapStructure<MouseMovementSignal> mapper =
new HeatmapStructure<MouseMovementSignal>(Height, Width);
mapper.LoadSignalsFromObjects(mouseSignals);
// .BMP Image is created inside of this method !!
mapper.IdentifyHeatRegions();
//MouseMovementSignal mms = argumentSignals[argumentSignals.Count - 1];
//Console.WriteLine("Last: " + mms.Channels[0].Name + ": " + mms.Channels[0].Values[0] + ", "
// + mms.Channels[1].Name + ": " + mms.Channels[1].Values[0]);
//finalHeatmap.Save("MyFirstBitmap.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
Console.WriteLine("Image actually Complete!!!!!!!!!!!!!!");
}
catch (Exception e)
{
Console.WriteLine("Error: " + e);
}
}
}
My Unity Script
public class HeatmapScript : MonoBehaviour {
private List<string> points;
private Camera cam;
private RawImage ri;
private string heatmapBmpPath = #"C:\Users\not-showing-you-my-file-structure-LOL\MyFirstBitmap.bmp";
private int frameCount = 0;
string pointsAsString = "";
Stopwatch sw;
// Use this for initialization
void Start() {
// Initialize the raw image.
cam = Camera.main;
GameObject imageObject = GameObject.FindGameObjectWithTag("imageView");
ri = imageObject.GetComponent<RawImage>();
// Initialize points list.
points = new List<string>();
sw = new Stopwatch();
sw.Start();
}
bool stop = false;
// Update is called once per frame.
void Update() {
float xValue = Input.mousePosition.x;
float yValue = Input.mousePosition.y;
Vector2 newPoint = new Vector2(xValue, yValue);
points.Add(newPoint.ToString());
int tSecs = 15000;// 15 seconds
// After 15 seconds of recording points pass them to the program that creates the heat map.
if (stop == false && sw.ElapsedMilliseconds > tSecs)
{
StartCoroutine("UpdateBMP");
UnityEngine.Debug.Log(points.Count);
stop = true;
}
//Update the raw image on the screen.
UnityEngine.Texture2D newTexture = CreateTextureFromBitmap(heatmapBmpPath);
//Set the RawImage to the size of the scren.
ri.texture = newTexture;
ri.rectTransform.sizeDelta = new Vector2(Screen.width, Screen.height);
frameCount++;
}
IEnumerator UpdateBMP()
{
// Show mouse position in unity environment
float xValue = Input.mousePosition.x;
float yValue = Input.mousePosition.y;
Vector2 newPoint = new Vector2(xValue, yValue);
points.Add(newPoint.ToString());
// EX:
// (123,123)|(123,123)|(123,123)|(123,123)|(123,123)|(123,123)
// display list contents without loop
pointsAsString = string.Join("|", points.ToArray());
// Every frame call Behavior's Program.cs that calls HeatmapStructure.cs to update .bmp file
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.FileName = #"C:\Users\not-showing-you-my-file-structure-LOL\ExternalProgram.exe";
processInfo.UseShellExecute = false;
processInfo.Arguments = pointsAsString;
Process process = Process.Start(processInfo);
yield return null;
}
private UnityEngine.Texture2D CreateTextureFromBitmap(string completeFilePath)
{
BMPLoader loader = new BMPLoader();
BMPImage img = loader.LoadBMP(completeFilePath);
UnityEngine.Texture2D myTexture = img.ToTexture2D();
UnityEngine.Debug.Log("File Size: " + img.header.filesize);
return myTexture;
}
}
HeatmapStructure.cs class
public class HeatmapStructure<T> where T : ISignal
{
public class COGPoint
{
public double X, Y, Z;
//public Color Color;
public byte Intensity;
public bool isD3Point = false; // 3D Point check
public const double DEFAULT_AXIS_LOC = 0.0001;
public COGPoint()
{
//Color = Color.Blue;
Intensity = 0;
}
// NOTE: double z has a default value therefore it is optional
public COGPoint(byte intensity, double x, double y, double z = DEFAULT_AXIS_LOC)
{
this.X = x;
this.Y = y;
this.Z = z; // Optional
//Color = Color.Blue; // Cold: Blue / Hot: Red
this.Intensity = intensity;
if (z != DEFAULT_AXIS_LOC)
{
isD3Point = true;
}
}
public override string ToString()
{
string output = (isD3Point == true) ?
("(x,y,z) " + X + "," + Y + "," + Z) : ("(x,y) " + X + "," + Y); // 3D : 2D
output += //" Color: " + Color.ToString() +
" Intensity: " + Intensity;
return output;
}
}
private List<COGPoint> points;
private int Height;
private int Width;
public HeatmapStructure(int Height, int Width)
{
this.Height = Height;
this.Width = Width;
points = new List<COGPoint>();
}
private Bitmap CreateIntensityMask(Bitmap bSurface, List<COGPoint> aHeatPoints)
{
// Create new graphics surface from memory bitmap
Graphics DrawSurface = Graphics.FromImage(bSurface);
// Set background color to white so that pixels can be correctly colorized
DrawSurface.Clear(Color.White);
// Traverse heat point data and draw masks for each heat point
foreach (COGPoint DataPoint in aHeatPoints)
{
// Render current heat point on draw surface
DrawHeatPoint(DrawSurface, DataPoint, 45);
}
return bSurface;
}
// TODO: How to draw updating Bitmap in unity in real time ??
private void DrawHeatPoint(Graphics Canvas, COGPoint HeatPoint, int Radius)
{
// Create points generic list of points to hold circumference points
List<Point> CircumferencePointsList = new List<Point>();
// Create an empty point to predefine the point struct used in the circumference loop
Point CircumferencePoint;
// Create an empty array that will be populated with points from the generic list
Point[] CircumferencePointsArray;
// Calculate ratio to scale byte intensity range from 0-255 to 0-1
float fRatio = 1F / Byte.MaxValue;
// Precalulate half of byte max value
byte bHalf = Byte.MaxValue / 2;
// Flip intensity on it's center value from low-high to high-low
int iIntensity = (byte)(HeatPoint.Intensity - ((HeatPoint.Intensity - bHalf) * 2));
// Store scaled and flipped intensity value for use with gradient center location
float fIntensity = iIntensity * fRatio;
// Loop through all angles of a circle
// Define loop variable as a double to prevent casting in each iteration
// Iterate through loop on 10 degree deltas, this can change to improve performance
for (double i = 0; i <= 360; i += 10)
{
// Replace last iteration point with new empty point struct
CircumferencePoint = new Point();
// Plot new point on the circumference of a circle of the defined radius
// Using the point coordinates, radius, and angle
// Calculate the position of this iterations point on the circle
CircumferencePoint.X = Convert.ToInt32(HeatPoint.X + Radius * Math.Cos(ConvertDegreesToRadians(i)));
CircumferencePoint.Y = Convert.ToInt32(HeatPoint.Y + Radius * Math.Sin(ConvertDegreesToRadians(i)));
// Add newly plotted circumference point to generic point list
CircumferencePointsList.Add(CircumferencePoint);
}
// Populate empty points system array from generic points array list
// Do this to satisfy the datatype of the PathGradientBrush and FillPolygon methods
CircumferencePointsArray = CircumferencePointsList.ToArray();
// Create new PathGradientBrush to create a radial gradient using the circumference points
PathGradientBrush GradientShaper = new PathGradientBrush(CircumferencePointsArray);
// Create new color blend to tell the PathGradientBrush what colors to use and where to put them
ColorBlend GradientSpecifications = new ColorBlend(3);
// Define positions of gradient colors, use intesity to adjust the middle color to
// show more mask or less mask
GradientSpecifications.Positions = new float[3] { 0, fIntensity, 1 };
// Define gradient colors and their alpha values, adjust alpha of gradient colors to match intensity
GradientSpecifications.Colors = new Color[3]
{
Color.FromArgb(0, Color.White),
Color.FromArgb(HeatPoint.Intensity, Color.Black),
Color.FromArgb(HeatPoint.Intensity, Color.Black)
};
// Pass off color blend to PathGradientBrush to instruct it how to generate the gradient
GradientShaper.InterpolationColors = GradientSpecifications;
// Draw polygon (circle) using our point array and gradient brush
Canvas.FillPolygon(GradientShaper, CircumferencePointsArray);
}
private double ConvertDegreesToRadians(double degrees)
{
double radians = (Math.PI / 180) * degrees;
return (radians);
}
// old name : button1_Click
public Bitmap IdentifyHeatRegions()
{
// Create new memory bitmap the same size as the picture box
Bitmap bMap = new Bitmap(Width, Height);
// Call CreateIntensityMask, give it the memory bitmap, and use it's output to set the picture box image
Bitmap bm = CreateIntensityMask(bMap, points);
Bitmap coloredBitmap = Colorize(bm, 243); // <-- NOTE: should be 255. But my palette.bmp is 243x5
coloredBitmap.Save("MyFirstBitmap.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
return coloredBitmap;
}
public static Bitmap Colorize(Bitmap Mask, byte Alpha)
{
// Create new bitmap to act as a work surface for the colorization process
Bitmap Output = new Bitmap(Mask.Width, Mask.Height, PixelFormat.Format32bppArgb);
// Create a graphics object from our memory bitmap so we can draw on it and clear it's drawing surface
Graphics Surface = Graphics.FromImage(Output);
Surface.Clear(Color.Transparent);
// Build an array of color mappings to remap our greyscale mask to full color
// Accept an alpha byte to specify the transparancy of the output image
ColorMap[] Colors = CreatePaletteIndex(Alpha);
// Create new image attributes class to handle the color remappings
// Inject our color map array to instruct the image attributes class how to do the colorization
ImageAttributes Remapper = new ImageAttributes();
try
{
Remapper.SetRemapTable(Colors);
}
catch (Exception e)
{
Console.WriteLine(e);
}
// Draw our mask onto our memory bitmap work surface using the new color mapping scheme
Surface.DrawImage(Mask, new Rectangle(0, 0, Mask.Width, Mask.Height), 0, 0, Mask.Width, Mask.Height, GraphicsUnit.Pixel, Remapper);
// Send back newly colorized memory bitmap
return Output;
}
private static ColorMap[] CreatePaletteIndex(byte Alpha)
{
ColorMap[] OutputMap = new ColorMap[Alpha + 1];
// Change this path to wherever you saved the palette image.
Bitmap Palette = (Bitmap)Bitmap.FromFile(#"C:\Users\cdowns\Desktop\palette.bmp");
// Loop through each pixel and create a new color mapping
try
{
for (int X = 0; X <= Alpha; X++)
{
OutputMap[X] = new ColorMap();
OutputMap[X].OldColor = Color.FromArgb(X, X, X);
OutputMap[X].NewColor = Color.FromArgb(Alpha, Palette.GetPixel(X, 0));
}
}
catch (Exception e) {
Console.WriteLine(e);
}
return OutputMap;
}
public void LoadSignalsFromObjects(List<T> allSignals) // ISignal Object
{
Random random = new Random();
foreach (T signal in allSignals)
{
COGPoint newPoint = new COGPoint();
if (allSignals[0].GetType() == typeof(MouseMovementSignal))
{
string axis1 = signal.Channels[0].Name;
List<double> value1 = signal.Channels[0].Values;
string axis2 = signal.Channels[1].Name;
List<double> value2 = signal.Channels[1].Values;
// Make sure to enter signals into database in this format
//Console.WriteLine(axis1 + " " + axis2);
newPoint.X = value1[0];
newPoint.Y = value2[0];
// TOOD: Implement
newPoint.Intensity = (byte)random.Next(0, 120);
// Display newPoint values
//Console.WriteLine("COGPoint Numbers: X: " + newPoint.X + " , Y: " + newPoint.Y
// + /*" Color: " + newPoint.Color + */" Intensity: " + newPoint.Intensity);
}
else if (allSignals[0].GetType() == typeof(EyePosition))
{
}
// Add to main list of heat points
points.Add(newPoint);
}
}
}
Expected result is that the .bmp image is created after the first 15 seconds.
(P.S. I am very new to both Unity and C# to I am probably doing this completely wrong. I am open to an entirely new idea for going about making this work. Thanks)
After doing a little more browsing on here for similar problems that other people have had I found this post pictureBox.Image.Save() in c# doesn't work. It answered my question regarding why my .bmp wasn't being generated.
It turns out that my program was working correctly after all. It was correctly generating the .bmp file. However, when I called ProcessStartInfo from within unity to run the ExternalProgram.exe that called Bitmap.save("filename.bmp") the working directory changed. Therefore, the image was not being saved in the location that I was expecting to find it in.

Categories

Resources