I am trying to implement the Transvoxel algorithm for a game I am working on but I'm noticing some weird issues in the mesh generated:
Not sure why there are gaps and why the sphere has fins behind it.
For some reason, the mesh has gaps between chunks, and it has these strange fins extending out behind it. I haven't been able to figure out why this is happening but I have an inkling it may have to do with either the function that generates the density values for each Chunk (16x16x16 Block of cells):
private float SampleDensity(float3 _point)
{
var _worldPos = (_point / (m_WorldRadius - 1.0f) - 0.5f) * m_VolumeFieldSize;
var _halfS = m_VolumeFieldSize / 2;
var _maxD= Magnitude(new float3(_halfS, _halfS, _halfS));
var _fudge = 1f;
var _density = Magnitude(_worldPos) / (_maxD + _fudge) - 0.5f;
var _noise = CalculateNoise(_worldPos);
_density += _noise;
return _density;
}
public void Execute()
{
for (int _z = 0; _z < m_ChunkSize; _z++)
{
for (int _y = 0; _y < m_ChunkSize; _y++)
{
for (int _x = 0; _x < m_ChunkSize; _x++)
{
var _point = (new float3(_x, _y, _z) + (m_GPosition)); // Multiplying or dividing this value adjusts the final mesh's scale.
var _valueAtPoint = SampleDensity(_point);
m_Cells[_z * m_ChunkSize * m_ChunkSize + _y * m_ChunkSize + _x] = _valueAtPoint;
}
}
}
}
, or the mesh generating code itself:
for (int _z = 0; _z < _chunk.m_ChunkSize; _z++)
{
for (int _y = 0; _y < _chunk.m_ChunkSize; _y++)
{
for (int _x = 0; _x < _chunk.m_ChunkSize; _x++)
{
var _cubeConfiguration = 0;
for (int _i = 0; _i < 8; _i++)
{
_cornerPos = CornerIndex[_i];
_densityValues[_i] = _chunk.GetCell(_x + _cornerPos.x, _y + _cornerPos.y, _z + _cornerPos.z);
if (_densityValues[_i] < _chunk.m_World.m_ISOLevel) _cubeConfiguration |= (1 << _i);
}
var _caseCode = (byte) _cubeConfiguration;
if (_caseCode == 0) continue;
for (int _i = 0; _i < _cornerNormals.Length; _i++)
{
_cornerPos = CornerIndex[_i];
_cornerNormals[_i] = new Vector3(
_chunk.GetCell(_x + _cornerPos.x - 1, _y + _cornerPos.y, _z + _cornerPos.z) - _chunk.GetCell(_x + _cornerPos.x + 1, _y + _cornerPos.y, _z + _cornerPos.z),
_chunk.GetCell(_x + _cornerPos.x, _y + _cornerPos.y - 1, _z + _cornerPos.z) - _chunk.GetCell(_x + _cornerPos.x, _y + _cornerPos.y + 1, _z + _cornerPos.z),
_chunk.GetCell(_x + _cornerPos.x, _y + _cornerPos.y, _z + _cornerPos.z - 1) - _chunk.GetCell(_x + _cornerPos.x, _y + _cornerPos.y, _z + _cornerPos.z + 1)
);
}
var _cellClass = Transvoxel.regularCellClass[_caseCode];
Debug.Log($"Cell Class {_cellClass}");
var _vertexLocations = Transvoxel.RegularVertexData[_caseCode];
var _cellData = Transvoxel.RegularCellDatas[_cellClass];
var _vertexCount = _cellData.GetVertexCount();
var _triangleCount = _cellData.GetTriangleCount();
var _indexOffset = _cellData.vertexIndex;
for (int _i = 0; _i < _vertexCount; _i++)
{
ushort _edge = (ushort)(_vertexLocations[_i] & 255);
byte _v0 = (byte)((_edge >> 4) & 0x0F); //First Corner Index
byte _v1 = (byte)(_edge & 0x0F); //Second Corner Index
float _t = (_densityValues[_v1]) / (_densityValues[_v1] - _densityValues[_v0]);
Vector3 _p0 = new Vector3((_x + CornerIndex[_v0].x), (_y + CornerIndex[_v0].y), (_z + CornerIndex[_v0].z));
Vector3 _p1 = new Vector3((_x + CornerIndex[_v1].x), (_y + CornerIndex[_v1].y), (_z + CornerIndex[_v1].z));
var _position = (_p0 * _t) + ((1 - _t) * _p1);
var _n0 = CalculateNormal(_chunk, new Vector3Int((int) _p0.x, (int) _p0.y, (int) _p0.z));
var _n1 = CalculateNormal(_chunk, new Vector3Int((int) _p1.x, (int) _p1.y, (int) _p1.z));
var _normal = (_n0 + _t * (_n1 - _n0)).normalized;
m_Normals.Add(_normal);
m_Vertices.Add(_position);
m_UVs.Add(UvOffset[m_VCase]);
m_VCase = (byte)(m_VCase == 3 ? 0 : m_VCase + 1);
m_LocalVertexMapping[_i] = (ushort)(m_Vertices.Count - 1);
}
for (int _t = 0; _t < _triangleCount; _t++)
{
int _tm = _t * 3;
m_Triangles.Add(m_LocalVertexMapping[_indexOffset[_tm]]);
m_Triangles.Add(m_LocalVertexMapping[_indexOffset[_tm + 1]]);
m_Triangles.Add(m_LocalVertexMapping[_indexOffset[_tm + 2]]);
}
}
}
}
I am at a complete loss and would really appreciate some help as I've been racking my brains for close to 2 months on this, along with reading several papers on different MC Algorithms (Lengyel's included) for potential inspiration. Thank You.
Related
I have been trying to generate a mesh using the code below, and have been successful generating a mesh with width and length of one, but any more and I get an error in the console that says
"Failed setting triangles. Some indices are referencing out of bounds vertices. IndexCount: 24, VertexCount: 9 UnityEngine.Mesh:set_triangles (int[])"
I have done all the math of calculating the triangles on paper, and all of the values are within the length of the vertices array, going from 0 to 8. I don't have any clue what I am doing wrong, or why this error message is getting thrown, so any help would be greatly appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeshGenerator : MonoBehaviour
{
Mesh mesh;
Vector3[] vertices;
int[] triangles;
public Mesh GenerateMesh(int mapWidth, int mapHeight)
{
mesh = new Mesh();
vertices = new Vector3[(mapHeight + 1) * (mapWidth + 1)];
triangles = new int[6 * (mapHeight * mapWidth)];
int index = 0;
for (int x = 0; x <= mapHeight; x++)
{
for (int y = 0; y <= mapWidth; y++)
{
vertices[index] = new Vector3(x, 0, y);
index += 1;
}
}
int z = 0;
for (int i = 0; i <= triangles.Length - 1; i += 6)
{
Debug.Log(i);
if (z == mapWidth)
{
triangles[i] = i + 1;
triangles[i + 1] = i + 2;
triangles[i + 2] = i + mapWidth + 3;
triangles[i + 3] = i + 1;
triangles[i + 4] = i + mapWidth + 3;
triangles[i + 5] = i + mapWidth + 2;
z = 1;
}
else
{
triangles[i] = i;
triangles[i + 1] = i + 1;
triangles[i + 2] = i + mapWidth + 2;
triangles[i + 3] = i;
triangles[i + 4] = i + mapWidth + 2;
triangles[i + 5] = i + mapWidth + 1;
z++;
}
}
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
return mesh;
}
}
I figured it out. The problem was I was using the index of the triangle array to calculate the index of the vertex array. Instead, I needed to use a separate variable (a) to calculate the vertex index. The new code is below.
int a = 0;
for (int i = 0; i < triangles.Length; i += 6)
{
Debug.Log(i);
if (z == mapWidth)
{
triangles[i] = a + 1;
triangles[i + 1] = a + 2;
triangles[i + 2] = a + mapWidth + 3;
triangles[i + 3] = a + 1;
triangles[i + 4] = a + mapWidth + 3;
triangles[i + 5] = a + mapWidth + 2;
z = 1;
a += 2;
}
else
{
triangles[i] = a;
triangles[i + 1] = a + 1;
triangles[i + 2] = a + mapWidth + 2;
triangles[i + 3] = a;
triangles[i + 4] = a + mapWidth + 2;
triangles[i + 5] = a + mapWidth + 1;
z++;
a++;
}
}
Well i've been doing some work with AI and object detection and have recently encounter somewhat of a problem with a model that i exported from CustomVision.
For the ones who know what i'm talking about, when you export a model from CustomVision you get a .cs file included that represents the class with everything you need to use the model.
And there starts all my problems.. first and most important one is that in one of the methods, specifically in the "ExtractBoxes" method receives a TensorFloat object and a float array of anchors.
Anyways.. inside this method there's 4 variables called "channels", "height" and "width" that come from a list inside of the TensorFloat object called "shape".
Given all this.. my question resides in the TensorFloat object, more specifically in how can i get the values for the variables "channels", "height" and "width" without having a TensorFloat object.
Below im going to include the code from the .cs file that im talking about.
Thanks in advance!
public async Task<IList<PredictionModel>> PredictImageAsync(VideoFrame image)
{
var imageWidth = image.SoftwareBitmap.PixelWidth;
var imageHeight = image.SoftwareBitmap.PixelHeight;
double ratio = Math.Sqrt((double)imageInputSize / (double)imageWidth / (double)imageHeight);
int targetWidth = 32 * (int)Math.Round(imageWidth * ratio / 32);
int targetHeight = 32 * (int)Math.Round(imageHeight * ratio / 32);
using (var resizedBitmap = await ResizeBitmap(image.SoftwareBitmap, targetWidth, targetHeight))
using (VideoFrame resizedVideoFrame = VideoFrame.CreateWithSoftwareBitmap(resizedBitmap))
{
var imageFeature = ImageFeatureValue.CreateFromVideoFrame(resizedVideoFrame);
var bindings = new LearningModelBinding(this.session);
bindings.Bind("input", imageFeature);
var result = await this.session.EvaluateAsync(bindings, "");
return Postprocess(result.Outputs["output"] as TensorFloat);
}
}
private List<PredictionModel> Postprocess(TensorFloat predictionOutputs)
{
var extractedBoxes = this.ExtractBoxes(predictionOutputs, ObjectDetection.Anchors);
return this.SuppressNonMaximum(extractedBoxes);
}
private ExtractedBoxes ExtractBoxes(TensorFloat predictionOutput, float[] anchors)
{
var shape = predictionOutput.Shape;
Debug.Assert(shape.Count == 4, "The model output has unexpected shape");
Debug.Assert(shape[0] == 1, "The batch size must be 1");
IReadOnlyList<float> outputs = predictionOutput.GetAsVectorView();
var numAnchor = anchors.Length / 2;
var channels = shape[1];
var height = shape[2];
var width = shape[3];
Debug.Assert(channels % numAnchor == 0);
var numClass = (channels / numAnchor) - 5;
Debug.Assert(numClass == this.labels.Count);
var boxes = new List<BoundingBox>();
var probs = new List<float[]>();
for (int gridY = 0; gridY < height; gridY++)
{
for (int gridX = 0; gridX < width; gridX++)
{
int offset = 0;
int stride = (int)(height * width);
int baseOffset = gridX + gridY * (int)width;
for (int i = 0; i < numAnchor; i++)
{
var x = (Logistic(outputs[baseOffset + (offset++ * stride)]) + gridX) / width;
var y = (Logistic(outputs[baseOffset + (offset++ * stride)]) + gridY) / height;
var w = (float)Math.Exp(outputs[baseOffset + (offset++ * stride)]) * anchors[i * 2] / width;
var h = (float)Math.Exp(outputs[baseOffset + (offset++ * stride)]) * anchors[i * 2 + 1] / height;
x = x - (w / 2);
y = y - (h / 2);
var objectness = Logistic(outputs[baseOffset + (offset++ * stride)]);
var classProbabilities = new float[numClass];
for (int j = 0; j < numClass; j++)
{
classProbabilities[j] = outputs[baseOffset + (offset++ * stride)];
}
var max = classProbabilities.Max();
for (int j = 0; j < numClass; j++)
{
classProbabilities[j] = (float)Math.Exp(classProbabilities[j] - max);
}
var sum = classProbabilities.Sum();
for (int j = 0; j < numClass; j++)
{
classProbabilities[j] *= objectness / sum;
}
if (classProbabilities.Max() > this.probabilityThreshold)
{
boxes.Add(new BoundingBox(x, y, w, h));
probs.Add(classProbabilities);
}
}
Debug.Assert(offset == channels);
}
}
Debug.Assert(boxes.Count == probs.Count);
return new ExtractedBoxes(boxes, probs);
}
Lets say a=x+y and b=2x-y and I want to plot a-b=0. I can manually rewrite this from (x+y)-(2x-y)=0 to y=.5x which makes it trivial to graph, but how do I rewrite it in code? Given x how do I calculate y if all I have is (x+y)-(2x-y)=0?
To be more specific, I am trying to graph the decision boundary of a neural network. I want to be able to change the layers and outputs at will, essentially changing the function I get as an output.
This is an example of an output I could get:
(x_1 w_2 + x_2 w_2 + b_1) w_7
+ (x_1 w_3 + x_2 w_4 + b_2) w_8
+ (x_1 w_5 + x_2 w_6 + b_3) w_9
+ b_4 (x_1 w_1 + x_2 w_2 + b_1) w_10
+ (x_1 w_3 + x_2 w_4 + b_2) w_11
+ (x_1 w_5 + x_2 w_6 + b_3) w_12
+ b_5
It's a 1 by 2 matrix and I know all values except x2 which is the y-axis. In order to draw the decision boundary I have to calculate a-b=0 where a and b both contain x and y. I can manually separate y to get y=... ,but that's not an option if the results in the output matrix change. How do I seperate/calculate the y?
I am using c# in Unity and passing the points on the graph into the LineRenderer.
Alright, I found the solution the same day of posting the question but had already been messing about for days. It turned out to be a math question after all.
Here's a link to the specific setup for the neural network using a linear activation: https://www.desmos.com/calculator/crmeebqnfb
I manually rewrote the matrix multiplication for this specific setup into a function and was looking for a way to do that for any size and number of invisible layers.
The solution I found is to separate the input matrix into x1 and x2 and separately do the matrix multiplication for them. The x1 value gets the biases added but the x2 doesn't and the first weight matrix has to be split in 2 so x1 can get multiplied with the first row and x2 with the second row.
If you then do the matrix multiplication from there you'll get two 2 matrices like this:
[firstx1answer secondx1answer] [firstx2answer secondx2answer]
And then you can put them into this function:
Edit for better clarification:
Maybe a bit confusing but here's my code. CreateDecisionBoundaryPoints is where this is implemented:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System.IO;
using System;
[ExecuteAlways]
public class Controller : MonoBehaviour
{
public Transform LineRenderer;
public GameObject textPrefab;
public GameObject pointPrefab;
public Transform weightsUI;
public Transform biasesUI;
[Range(.001f, .1f)] public float delta;
public int numberOfHiddenLayers;
public bool debugWeightMatrices;
public bool debugBiasMatrices;
[HideInInspector] public string[] dataValues;
private void Start()
{
if (Application.isPlaying)
{
//read file
int numberOfLines;
dataValues = ReadData("D:\\Documents\\Unity Projects\\Learning Machine Learning\\Assets\\Data.csv", out numberOfLines);
int numOfOutputNeurons = CreatePointsUI(numberOfLines, dataValues);
//create layerSizes for example [2,3,2]
int[] layerSizes = new int[numberOfHiddenLayers + 2];
layerSizes[0] = (dataValues.Length / numberOfLines) - 1;
layerSizes[numberOfHiddenLayers + 1] = numOfOutputNeurons;
for (int i = 0; i < numberOfHiddenLayers; i++)
{
layerSizes[i+1] = Mathf.Max((dataValues.Length / numberOfLines) - 1, numOfOutputNeurons) + 1;
}
//create the actual matrices
List<float[,]> weights = new List<float[,]>();
List<float[]> biases = new List<float[]>();
MakeTheMatrices(layerSizes, out weights, out biases);
//fill weights with random values
RandomlyFillMatrices(weights);
//print matrices to make sure they're the right size and filled randomly
if (debugWeightMatrices)
Debug.Log(PrintMatrices(weights, "Weight Matrices"));
if (debugBiasMatrices)
Debug.Log(PrintMatrices(biases, "Bias Matrices"));
LineRenderer.GetComponent<DrawDecisionBoundary>().DrawLine(CreateDecisionBoundaryPoints(weights, biases, delta));
}
}
public struct OutputNeuronsAndColours
{
public string value;
public Color color;
public OutputNeuronsAndColours(string value, Color color)
{
this.value = value;
this.color = color;
}
}
public void DoTheWeightsStufUI(int weights)
{
int cwn = 0;
List<Transform> ws = new List<Transform>();
foreach (Transform child in weightsUI)
{
cwn++;
ws.Add(child);
}
int wta = weights - cwn;
for (int i = wta; i < 0; i++)
{
cwn--;
DestroyImmediate(ws[cwn].gameObject);
ws.RemoveAt(cwn);
}
for (int i = wta; i > 0; i--)
{
cwn++;
GameObject weight = Instantiate(textPrefab, weightsUI);
weight.GetComponentInChildren<TMP_Text>().SetText("W" + cwn.ToString());
}
}
public void DoTheBiasesStufUI(int biases)
{
int cbn = 0;
List<Transform> bs = new List<Transform>();
foreach (Transform child in biasesUI)
{
cbn++;
bs.Add(child);
}
int bta = biases - cbn;
for (int i = bta; i < 0; i++)
{
cbn--;
DestroyImmediate(bs[cbn].gameObject);
bs.RemoveAt(cbn);
}
for (int i = bta; i > 0; i--)
{
cbn++;
GameObject bias = Instantiate(textPrefab, biasesUI);
bias.GetComponentInChildren<TMP_Text>().SetText("B" + cbn.ToString());
}
}
string[] ReadData(string path, out int numberOfLines)
{
List<string> data_values = new List<string>();
StreamReader strReader = new StreamReader(path);
bool endOfFile = false;
int numOfLines = 0;
while (!endOfFile)
{
string data_string = strReader.ReadLine();
if (data_string == null)
{
endOfFile = true;
break;
}
else
numOfLines += 1;
data_values.AddRange(data_string.Split(','));
}
numberOfLines = numOfLines;
return data_values.ToArray();
}
int CreatePointsUI(int numberOfLines, string[] dataValues)
{
string[] possibleOutputs = new string[numberOfLines];
for (int i = 0; i < numberOfLines; i++)
{
possibleOutputs[i] = dataValues[(i * (dataValues.Length / numberOfLines)) + ((dataValues.Length / numberOfLines) - 1)];
}
List<OutputNeuronsAndColours> outputNeurons = new List<OutputNeuronsAndColours>(possibleOutputs.Length);
for (int i = 0; i < possibleOutputs.Length; i++)
{
bool contains = false;
for (int x = 0; x < outputNeurons.Count; x++)
{
if (possibleOutputs[i] == outputNeurons[x].value)
contains = true;
}
if (!contains)
outputNeurons.Add(new OutputNeuronsAndColours(possibleOutputs[i], new Color(UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f))));
}
for (int i = 0; i < numberOfLines; i++)
{
GameObject point = Instantiate(pointPrefab);
point.transform.position = new Vector2(float.Parse(dataValues[i * (dataValues.Length / numberOfLines)]), float.Parse(dataValues[(i * (dataValues.Length / numberOfLines)) + 1]));
foreach (OutputNeuronsAndColours value in outputNeurons)
{
if (value.value == dataValues[(i * (dataValues.Length / numberOfLines)) + ((dataValues.Length / numberOfLines) - 1)])
point.GetComponent<SpriteRenderer>().color = value.color;
}
}
return outputNeurons.Count;
}
public static void MakeTheMatrices(int[] layerSizes, out List<float[,]> weights, out List<float[]> biases)
{
List<float[,]> tempWeights = new List<float[,]>();
List<float[]> tempBiases = new List<float[]>();
for (int i = 0; i < layerSizes.Length - 1; i++)
{
tempWeights.Add(new float[layerSizes[i], layerSizes[i + 1]]);
}
for (int i = 1; i < layerSizes.Length; i++)
{
List<float> temp = new List<float>();
for (int x = 0; x < layerSizes[i]; x++)
temp.Add(0);
tempBiases.Add(temp.ToArray());
}
weights = tempWeights;
biases = tempBiases;
}
public static void RandomlyFillMatrices(List<float[,]> matrices)
{
foreach (float[,] matrix in matrices)
{
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int x = 0; x < matrix.GetLength(1); x++)
{
matrix[i, x] = UnityEngine.Random.Range(-3f, 3f);
}
}
}
}
public static string PrintMatrices(List<float[,]> matrices, string name = "Count")
{
string returnString = matrices.Count + " " + name;
foreach (float[,] matrix in matrices)
{
returnString += " (" + matrix.GetLength(0) + ", " + matrix.GetLength(1) + ")";
for (int i = 0; i < matrix.GetLength(0); i++)
{
string log = "";
if (i == 0)
log += "[";
else
log += " ";
for (int x = 0; x < matrix.GetLength(1); x++)
{
log += matrix[i, x];
if(x != matrix.GetLength(1) - 1)
log += " ";
}
if (i == matrix.GetLength(0) - 1)
log += "]";
Debug.Log(log);
}
}
return returnString;
}
public static string PrintMatrices(List<float[]> matrices, string name = "Count")
{
string returnString = matrices.Count + " " + name;
foreach (float[] matrix in matrices)
{
returnString += " (" + matrix.Length + ")";
string log = "[";
for (int i = 0; i < matrix.Length; i++)
{
log += matrix[i];
if (i != matrix.Length - 1)
log += " ";
}
log += "]";
Debug.Log(log);
}
return returnString;
}
private Vector3[] CreateDecisionBoundaryPoints(List<float[,]> weights, List<float[]> biases, float delta)
{
//check whether there are exactly 2 input neurons
if (weights[0].GetLength(0) != 2)
Debug.LogError("Not exactly 2 input neurons!");
//check whether there are exactly 2 output neurons
if (biases[biases.Count - 1].Length != 2)
Debug.LogError("Not exactly 2 output neurons!");
//create the values for the first layer
float[] weightsForFirstLayerX = new float[weights[0].GetLength(1)];
for (int i = 0; i < weights[0].GetLength(1); i++)
{
weightsForFirstLayerX[i] = weights[0][0, i];
}
float[] denominatorValuesFirstLayer = new float[weights[0].GetLength(1)];
for (int i = 0; i < weights[0].GetLength(1); i++)
{
denominatorValuesFirstLayer[i] = weights[0][1, i];
}
List<Vector3> pointsForGraph = new List<Vector3>();
//Calculate the y value(s) for each x with interval delta
for (float x = -.04f; x <= 1 + delta; x += delta)
{
float[] numeratorValuesFirstLayer = new float[weightsForFirstLayerX.Length];
for (int i = 0; i < weightsForFirstLayerX.Length; i++)
numeratorValuesFirstLayer[i] = x * weightsForFirstLayerX[i] + biases[0][i];
//get the row matrices for the decision boundary function
float[] numeratorResults = PassValuesThroughMatrices(numeratorValuesFirstLayer, weights, biases, true);
float[] denominatorResults = PassValuesThroughMatrices(denominatorValuesFirstLayer, weights, biases, false);
float y = (numeratorResults[1] - numeratorResults[0]) / (denominatorResults[0] - denominatorResults[1]);
pointsForGraph.Add(new Vector3(x, y, -1));
}
return pointsForGraph.ToArray();
}
private float[] PassValuesThroughMatrices(float[] values, List<float[,]> weights, List<float[]> biases, bool isNumerator)
{
float[] previousLayer = values;
//loop passing the previous layer values through the current layer: values = values * weights + biases
for (int i = 1; i < weights.Count; i++)
{
float[] temp = new float[weights[i].GetLength(1)];
//loop through the colums in the weight matrix
for (int v = 0; v < weights[i].GetLength(1); v++)
{
float value = 0;
//loop through the rows in the weight matrix
for (int b = 0; b < weights[i].GetLength(0); b++)
value += previousLayer[b] * weights[i][b, v];
if (isNumerator)
value += biases[i][v];
temp[v] = value;
}
previousLayer = temp;
}
//return the last itteration of values
return previousLayer;
}
}
I'm trying to create a simple edge detection filter. And as I said it works with only one image. I'm trying to create this filter with 2 steps.
Blurring image (with meanfilter)
Calculate ( Original image-Blurring image)
The first step works well. And code of second one is simple like first one. But I see an error message:
System.ArgumentOutOfRangeException: 'Parameter must be positive and < Height.
Parameter name: y'
Working image:https://i.hizliresim.com/dLXkbn.png
My code:
public void edgedetectionfilter( )
{
Bitmap InputPicture,BlurredPicture, OutputPicture;
InputPicture = new Bitmap(pBox_SOURCE.Image);
BlurredPicture = new Bitmap(pBox_PROCESSED.Image);
int PicWidth = InputPicture.Width;
int PicHeight= InputPicture.Height;
OutputPicture = new Bitmap(PicWidth, PicHeight);
OutputPicture = InputPicture;
int x, y, difR, difG, difB;
Color OrgPicColoValue,BluredPicColorValue;
for (x = 0; x < PicWidth; x++)
{
for (y = 0; y < PicWidth; y++)
{
BluredPicColorValue = BlurredPicture.GetPixel(x, y);
OrgPicColoValue = InputPicture.GetPixel(x, y); //ERROR LINE
difR = Convert.ToInt16(OrgPicColoValue.R -BluredPicColorValue.R);
difG = Convert.ToInt16(OrgPicColoValue.G- BluredPicColorValue.G );
difB = Convert.ToInt16(OrgPicColoValue.B- BluredPicColorValue.B);
if (difR > 255) difR = 255;
if (difG > 255) difG = 255;
if (difB > 255) difB = 255;
if (difR < 0) difR = 0;
if (difG < 0) difG = 0;
if (difB < 0) difB = 0;
OutputPicture.SetPixel(x, y, Color.FromArgb(difR, difG, difB));
}
}
pBoxMedian.Image = OutputPicture;
}
public void meanfilter(int p)
//KERNELSIZE=P
{
if (sliderKernel.Value % 2 == 0)
{
MessageBox.Show("Enter an odd number");
return;
}
Color ColorValue;
Bitmap InputPicture, OutputPicture;
InputPicture = new Bitmap(pBox_SOURCE.Image);
int PicWidth = InputPicture.Width;
int PicHeight= InputPicture.Height;
OutputPicture = new Bitmap(PicWidth, PicHeight);
OutputPicture = InputPicture;
int x, y, i, j, sumR, sumG, sumB, avgR, avgG, avgB;
for (x = (KernelSize - 1) / 2; x < PicWidth - (KernelSize - 1) / 2; x++)
{
for (y = (KernelSize - 1) / 2; y < PicHeight - (KernelSize- 1) / 2; y++)
{
toplamR = 0;
toplamG = 0;
toplamB = 0;
for (i = -((KernelSize - 1) / 2); i <= (KernelSize - 1) / 2; i++)
{
for (j = -((KernelSize - 1) / 2); j <= (KernelSize - 1) / 2; j++)
{
ColorValue= InputPicture.GetPixel(x + i, y + j);
sumR = sumR + ColorValue.R;
sumG = sumG + ColorValue.G;
sumB = sumB + ColorValue.B;
}
}
avgR = sumR / (KernelSize * KernelSize );
avgG = sumG / (KernelSize *KernelSize );
avgB = sumB / (KernelSize * KernelSize );
OutputPicture.SetPixel(x, y, Color.FromArgb(avgR, avgG, avgB));
}
}
pBox_PROCESSED.Image = OutputPicture;
}
You compare y < PicWidth, whereas you probably want y < PicHeight. Is the image it worked on square, by chance?
I have the method that does a calculation and adds the data to a collection list. Below is my code
IterateDtColl iterateDataList = new IterateDtColl();
double answer;
//Array to hold the previous initail tempreture
double[] TempArray = new double[9];
for (int tVal = 0; tVal < exdatalist.count(); tVal++)
{
ValidateDataColl validatelist = new ValidateDataColl();
//Assign my initial tempreture
if (iterateDataList.count() > 0)
{
TempArray[0] = iterateDataList.getexceldata(tVal - 1).Pi1;
TempArray[1] = iterateDataList.getexceldata(tVal - 1).Pi2;
TempArray[2] = iterateDataList.getexceldata(tVal - 1).Pi3;
TempArray[3] = iterateDataList.getexceldata(tVal - 1).Pi4;
TempArray[4] = iterateDataList.getexceldata(tVal - 1).Pi5;
TempArray[5] = iterateDataList.getexceldata(tVal - 1).Pi6;
TempArray[6] = iterateDataList.getexceldata(tVal - 1).Pi7;
TempArray[7] = iterateDataList.getexceldata(tVal - 1).Pi8;
TempArray[8] = iterateDataList.getexceldata(tVal - 1).Pi9;
}
else
{
TempArray[0] = Convert.ToDouble(initProbTxtBx.Text);
TempArray[1] = TempArray[0];
TempArray[2] = TempArray[0];
TempArray[3] = TempArray[0];
TempArray[4] = TempArray[0];
TempArray[5] = TempArray[0];
TempArray[6] = TempArray[0];
TempArray[7] = TempArray[0];
TempArray[8] = TempArray[0];
}
//Holds Value for last calculated values..
double[] LastCalValue = new double[9];
for (int iVal = 0; iVal < 9; iVal++)
{
answer = 0.0;
if (iVal == 0)
{
answer = (TempArray[iVal] + (r_val(dxval(lval, nval)) * (exdatalist.getexceldata(tVal).CentreTemp + initVal))) / (1 + (2 * r_val(dxval(lval, nval))));
}
else if (iVal == 8)
{
answer = (TempArray[iVal] + (r_val(dxval(lval, nval)) * (LastCalValue[iVal - 1] + exdatalist.getexceldata(tVal).SurfaceTemp))) / (1 + (2 * r_val(dxval(lval, nval))));
}
else
{
answer = (TempArray[iVal] + (r_val(dxval(lval, nval)) * (LastCalValue[iVal - 1] + initVal))) / (1 + (2 * r_val(dxval(lval, nval))));
}
//Hold the values at the present index so it can be used at the next index
LastCalValue[iVal] = answer;
//Adds the data to be validated to my collection list
validatelist.addvaliddt(new ValidateDataCl(initVal, LastCalValue[iVal], TempArray[iVal]));
}
I want to check that the difference between the initVal and LastCalValue[index] in the validatelist is less than 0.0001, if it is not, then do the calculation below till the condition is met.
for (int check = 0; check < validate.count(); check++)
{
double newAnswer;
double NewVal = 0.0;
if (check == 0)
{
//Set my new value to the value at the next index(Which then becomes my guess)
NewVal = validate.getvaliddata(check + 1).NewValue;
newAnswer = (validate.getvaliddata(check).InitTemp + (r_val(dxval(lval, nval)) * (CentreTemp + NewVal))) / (1 + (2 * r_val(dxval(lval, nval))));
}
else if (check == 8)
{
NewVal = OldVal[check - 1];
newAnswer = (validate.getvaliddata(check).InitTemp + (r_val(dxval(lval, nval)) * (NewVal + SurfaceTemp))) / (1 + (2 * r_val(dxval(lval, nval))));
}
else
{
NewVal = validate.getvaliddata(check + 1).NewValue;
newAnswer = (validate.getvaliddata(check).InitTemp + (r_val(dxval(lval, nval)) * (OldVal[check - 1] + NewVal))) / (1 + (2 * r_val(dxval(lval, nval))));
}
validate.getvaliddata(check).InitGuess = NewVal;
validate.getvaliddata(check).NewValue = newAnswer;
OldVal[check] = newAnswer;
}
//ValidateDataColl ValidatedList = CalNewData(validatelist, exdatalist.getexceldata(tVal).CentreTemp, exdatalist.getexceldata(tVal).SurfaceTemp);
iterateDataList.additerdt(new IterateClass(exdatalist.getexceldata(tVal).CentreTemp, ValidatedList.getvaliddata(0).NewValue, ValidatedList.getvaliddata(1).NewValue, ValidatedList.getvaliddata(2).NewValue, ValidatedList.getvaliddata(3).NewValue, ValidatedList.getvaliddata(4).NewValue, ValidatedList.getvaliddata(5).NewValue, ValidatedList.getvaliddata(6).NewValue, ValidatedList.getvaliddata(7).NewValue, ValidatedList.getvaliddata(8).NewValue, exdatalist.getexceldata(tVal).SurfaceTemp));
}
return iterateDataList;
How can I do that?