C# 任意图形加权 Voronoi 图生成
最编程
2024-06-27 08:42:07
...
距离变换是计算并标识空间点(对目标点)距离的过程,它最终把二值图像变换为灰度图像[1](其中每个栅格的灰度值等于它到最近目标点的距离)。目前距离变换被广泛应用于计算机图形学、GIS空间分析和模式识别等领域。 按距离类型划分,距离变换可分为:非欧氏距离变换和欧氏距离变换(EDT)。其中EDT精度高,与实际距离相符,应用更广泛。目前随着应用的需要,已经有多种EDT算法[2-6]。按变换方式分,这些算法可以分为:基于目标点变换算法[2,3]和基于背景点变换算法[4-6],其中基于目标点变换算法又可分为:传播算法[4]、光栅扫描算法[5]和独立扫描算法[6]。上述算法大多致力于算法效率和完全性上的研究,其算法扩展性十分有限。 为此,作者提出了一种新的EDT算法,该算法在原有光栅扫描算法基础上,进行了改进,算法在信息传递的时候,用最近目标点的行列号代替与最近目标点行列号的差异,这样通过这些行列号可以轻松实现欧氏距离变换。和原有算法相比,该算法扩展后可以用于加权欧氏距离变换、任意图形加权Voronoi图的生成。以下为实现代码: //VoronoiClass.cs文件 using System; using System.Collections.Generic; using System.Text; using System.Collections; [assembly: CLSCompliant(true)] namespace Voronoi { public class VoronoiClass : IVoronoiClass { private struct RC { public int i; public int j; } private class Mark { private int o_x; public int O_x { get { return o_x; } set { o_x = value; } } private int o_y; public int O_y { get { return o_y; } set { o_y = value; } } private double weight; public double Weight { get { return weight; } set { weight = value; } } private double o_num; public double O_num { get { return o_num; } set { o_num = value; } } } private class Recode { private int o_x; public int O_x { get { return o_x; } set { o_x = value; } } private int o_y; public int O_y { get { return o_y; } set { o_y = value; } } private double o_num; public double O_num { get { return o_num; } set { o_num = value; } } private double weight; public double Weight { get { return weight; } set { weight = value; } } private double distance; public double Distance { get { return distance; } set { distance = value; } } } //公共变量 Mark[,] T; int max = 10000000; Array IVoronoiClass.doVoronoi(Array pixelData, int W, int H) { T = new Mark[W + 2, H + 2];//加个框框 Array ResultData; ///////////////////////////////预处理 for (int i = 0; i < W + 2; i++) for (int j = 0; j < H + 2; j++) { T[i, j] = new Mark(); double weight; try { weight = Convert.ToDouble(pixelData.GetValue(i - 1, j - 1)); } catch (Exception ex) { weight = 0; string a = ex.Message;//日魂归 } if (weight > 0)//目标 { T[i, j].O_x = i; T[i, j].O_y = j; T[i, j].Weight = weight; T[i, j].O_num = 0; } else//背景 { T[i, j].O_x = max; T[i, j].O_y = max; T[i, j].Weight = 1.1; T[i, j].O_num = 0; } } double num = 1; for (int i = 0; i < W + 2; i++) for (int j = 0; j < H + 2; j++) { if (T[i, j].Weight != 1.1 && T[i, j].O_num == 0) { T[i, j].O_num = num; Stack process = new Stack(); FindPolygon(process, i, j,W,H); while (process.Count > 0) { RC rc = (RC)process.Pop(); FindPolygon(process, rc.i, rc.j,W,H); } GC.Collect(); num++; } } //////////////////////////////上行扫描 Recode[] recode = new Recode[9]; for (int i = 1; i < W + 1; i++) for (int j = 1; j < H + 1; j++) { recode[1] = new Recode(); recode[1].Distance = Math.Sqrt(Math.Pow(i - T[i, j - 1].O_x, 2) + Math.Pow(j - T[i, j - 1].O_y, 2)) / T[i, j - 1].Weight; recode[1].O_x = T[i, j - 1].O_x; recode[1].O_y = T[i, j - 1].O_y; recode[1].O_num = T[i, j - 1].O_num; recode[1].Weight = T[i, j - 1].Weight; recode[2] = new Recode(); recode[2].Distance = Math.Sqrt(Math.Pow(i - T[i - 1, j - 1].O_x, 2) + Math.Pow(j - T[i - 1, j - 1].O_y, 2)) / T[i - 1, j - 1].Weight; recode[2].O_x = T[i - 1, j - 1].O_x; recode[2].O_y = T[i - 1, j - 1].O_y; recode[2].O_num = T[i - 1, j - 1].O_num; recode[2].Weight = T[i - 1, j - 1].Weight; recode[3] = new Recode(); recode[3].Distance = Math.Sqrt(Math.Pow(i - T[i - 1, j].O_x, 2) + Math.Pow(j - T[i - 1, j].O_y, 2)) / T[i - 1, j].Weight; recode[3].O_x = T[i - 1, j].O_x; recode[3].O_y = T[i - 1, j].O_y; recode[3].O_num = T[i - 1, j].O_num; recode[3].Weight = T[i - 1, j].Weight; recode[4] = new Recode(); { recode[4].Distance = Math.Sqrt(Math.Pow(i - T[i - 1, j + 1].O_x, 2) + Math.Pow(j - T[i - 1, j + 1].O_y, 2)) / T[i - 1, j + 1].Weight; recode[4].O_x = T[i - 1, j + 1].O_x; recode[4].O_y = T[i - 1, j + 1].O_y; recode[4].O_num = T[i - 1, j + 1].O_num; recode[4].Weight = T[i - 1, j + 1].Weight; } for (int k = 1; k < 5; k++) { double distance = Math.Sqrt(Math.Pow(i - T[i, j].O_x, 2) + Math.Pow(j - T[i, j].O_y, 2)) / T[i, j].Weight; if (recode[k].Distance < distance) { T[i, j].O_x = recode[k].O_x; T[i, j].O_y = recode[k].O_y; T[i, j].O_num = recode[k].O_num; T[i, j].Weight = recode[k].Weight; } } } //////////////////////上行扫描结束 ///////////////////////下行扫描 for (int i = W; i > 0; i--) for (int j = H; j > 0; j--) { recode[5] = new Recode(); recode[5].Distance = Math.Sqrt(Math.Pow(i - T[i, j + 1].O_x, 2) + Math.Pow(j - T[i, j + 1].O_y, 2)) / T[i, j + 1].Weight; recode[5].O_x = T[i, j + 1].O_x; recode[5].O_y = T[i, j + 1].O_y; recode[5].O_num = T[i, j + 1].O_num; recode[5].Weight = T[i, j + 1].Weight; recode[6] = new Recode(); recode[6].Distance = Math.Sqrt(Math.Pow(i - T[i + 1, j + 1].O_x, 2) + Math.Pow(j - T[i + 1, j + 1].O_y, 2)) / T[i + 1, j + 1].Weight; recode[6].O_x = T[i + 1, j + 1].O_x; recode[6].O_y = T[i + 1, j + 1].O_y; recode[6].O_num = T[i + 1, j + 1].O_num; recode[6].Weight = T[i + 1, j + 1].Weight; recode[7] = new Recode(); recode[7].Distance = Math.Sqrt(Math.Pow(i - T[i + 1, j].O_x, 2) + Math.Pow(j - T[i + 1, j].O_y, 2)) / T[i + 1, j].Weight; recode[7].O_x = T[i + 1, j].O_x; recode[7].O_y = T[i + 1, j].O_y; recode[7].O_num = T[i + 1, j].O_num; recode[7].Weight = T[i + 1, j].Weight; recode[8] = new Recode(); { recode[8].Distance = Math.Sqrt(Math.Pow(i - T[i + 1, j - 1].O_x, 2) + Math.Pow(j - T[i + 1, j - 1].O_y, 2)) / T[i + 1, j - 1].Weight; recode[8].O_x = T[i + 1, j - 1].O_x; recode[8].O_y = T[i + 1, j - 1].O_y; recode[8].O_num = T[i + 1, j - 1].O_num; recode[8].Weight = T[i + 1, j - 1].Weight; } for (int k = 5; k < 9; k++) { double distance = Math.Sqrt(Math.Pow(i - T[i, j].O_x, 2) + Math.Pow(j - T[i, j].O_y, 2)) / T[i, j].Weight; if (recode[k].Distance < distance) { T[i, j].O_x = recode[k].O_x; T[i, j].O_y = recode[k].O_y; T[i, j].O_num = recode[k].O_num; T[i, j].Weight = recode[k].Weight; } } } ///////////////////下行扫描结束 ResultData = Array.CreateInstance(typeof(Byte), W, H); for (int i = 1; i < W + 1; i++) for (int j = 1; j < H + 1; j++) { ResultData.SetValue(Convert.ToByte(T[i, j].O_num), i - 1, j - 1); } return ResultData; } private void digui(int i, int j,int W,int H) { #region #endregion if (i > 1) { if (T[i - 1, j].Weight != 1.1 && T[i - 1, j].O_num == 0) { T[i - 1, j].O_num = T[i, j].O_num; digui(i - 1, j,W,H); } } if (i > 1 && j > 1) { if (T[i - 1, j - 1].Weight != 1.1 && T[i - 1, j - 1].O_num == 0) { T[i - 1, j - 1].O_num = T[i, j].O_num; digui(i - 1, j - 1,W,H); } } if (j > 1) { if (T[i, j - 1].Weight != 1.1 && T[i, j - 1].O_num == 0) { T[i, j - 1].O_num = T[i, j].O_num; digui(i, j - 1,W,H); } } if (i < W && j > 0) { if (T[i + 1, j - 1].Weight != 1.1 && T[i + 1, j - 1].O_num == 0) { T[i + 1, j - 1].O_num = T[i, j].O_num; digui(i + 1, j - 1,W,H); } } if (i < W) { if (T[i + 1, j].Weight != 1.1 && T[i + 1, j].O_num == 0) { T[i + 1, j].O_num = T[i, j].O_num; digui(i + 1, j,W,H); } } if (i < W && j < H) { if (T[i + 1, j + 1].Weight != 1.1 && T[i + 1, j + 1].O_num == 0) { T[i + 1, j + 1].O_num = T[i, j].O_num; digui(i + 1, j + 1,W,H); } } if (j < H) { if (T[i, j + 1].Weight != 1.1 && T[i, j + 1].O_num == 0) { T[i, j + 1].O_num = T[i, j].O_num; digui(i, j + 1,W,H); } } if (i > 1 && j < H) { if (T[i - 1, j + 1].Weight != 1.1 && T[i - 1, j + 1].O_num == 0) { T[i - 1, j + 1].O_num = T[i, j].O_num; digui(i - 1, j + 1,W,H); } } GC.Collect(); } private void FindPolygon(Stack process, int i, int j,int W,int H) { if (i > 1) { if (T[i - 1, j].Weight != 1.1 && T[i - 1, j].O_num == 0) { T[i - 1, j].O_num = T[i, j].O_num; AddValue(process, i - 1, j); } } if (i > 1 && j > 1) { if (T[i - 1, j - 1].Weight != 1.1 && T[i - 1, j - 1].O_num == 0) { T[i - 1, j - 1].O_num = T[i, j].O_num; AddValue(process, i - 1, j - 1); } } if (j > 1) { if (T[i, j - 1].Weight != 1.1 && T[i, j - 1].O_num == 0) { T[i, j - 1].O_num = T[i, j].O_num; AddValue(process, i, j - 1); } } if (i < W && j > 0) { if (T[i + 1, j - 1].Weight != 1.1 && T[i + 1, j - 1].O_num == 0) { T[i + 1, j - 1].O_num = T[i, j].O_num; AddValue(process, i + 1, j - 1); } } if (i < W) { if (T[i + 1, j].Weight != 1.1 && T[i + 1, j].O_num == 0) { T[i + 1, j].O_num = T[i, j].O_num; AddValue(process, i + 1, j); } } if (i < W && j < H) { if (T[i + 1, j + 1].Weight != 1.1 && T[i + 1, j + 1].O_num == 0) { T[i + 1, j + 1].O_num = T[i, j].O_num; AddValue(process, i + 1, j + 1); } } if (j < H) { if (T[i, j + 1].Weight != 1.1 && T[i, j + 1].O_num == 0) { T[i, j + 1].O_num = T[i, j].O_num; AddValue(process, i, j + 1); } } if (i > 1 && j < H) { if (T[i - 1, j + 1].Weight != 1.1 && T[i - 1, j + 1].O_num == 0) { T[i - 1, j + 1].O_num = T[i, j].O_num; AddValue(process, i - 1, j + 1); } } } private void AddValue(Stack process, int i, int j) { { RC rc = new RC(); rc.i = i; rc.j = j; process.Push(rc); } } } } using System; namespace Voronoi { public interface IVoronoiClass { Array doVoronoi(Array pixelData, int W, int H); } } using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; using System.IO; using System.Collections; namespace GLCStatisticalAnalysis { public partial class BuiltVoronoiFrom : Form { public BuiltVoronoiFrom() { InitializeComponent(); worker.WorkerReportsProgress = true; worker.WorkerSupportsCancellation = true; //正式做事情的地方 worker.DoWork += new DoWorkEventHandler(DoWork); //任务完称时要做的,比如提示等等 worker.ProgressChanged += new ProgressChangedEventHandler(ProgessChanged); //任务进行时,报告进度 worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteWork); } Thread mainThread; public BackgroundWorker worker = new BackgroundWorker(); bool progress = true; //进度条控制参 VoronoiProcess pProcess = new VoronoiProcess(); string classField; string cellSize; private void OK_Click(object sender, EventArgs e) { bool start = checkFilePath(); if (start) { classField = comboBox1.Text; cellSize = textBo
上一篇: voronoi tessellation