C#任意图形加权Voronoi图生成

2022/6/12 1:20:13

本文主要是介绍C#任意图形加权Voronoi图生成,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

    距离变换是计算并标识空间点(对目标点)距离的过程,它最终把二值图像变换为灰度图像[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 = textBox2.Text;
                mainThread = new Thread(mainThreadProcess);
                mainThread.SetApartmentState(ApartmentState.STA);
                mainThread.Start();
                worker.RunWorkerAsync();//进度条控制
                this.panel_hidden.Enabled = false;
                OK.Enabled = false;
            }
        }
        private bool checkFilePath()
        {


            bool start = true;
            if (textBox1.Text == "")
            { MessageBox.Show("请输入要素文件!"); start = false; return start; }
            else if (textBox2.Text == "")
            { MessageBox.Show("请输入影像文件!"); start = false; return start; }
            
            else if (comboBox1.Text == "")
            { MessageBox.Show("请输入权重字段!"); start = false; return start; }
            else if (textBox2.Text == "")
            { MessageBox.Show("请输入精度!"); start = false; return start; }
            else if (!File.Exists(textBox1.Text))
            { MessageBox.Show("要素文件不存在!"); start = false; return start; }
           
            else if (File.Exists(textBox3.Text))
            {
                try { System.IO.File.Delete(textBox3.Text); }
                catch (Exception ex)
                {
                    start = false;
                    MessageBox.Show(ex.Message);
                    return start;
                }
            }
            else
            {
                //检验输出路径是否存在
                string outPath = textBox3.Text;
                int index = outPath.LastIndexOf("\\");
                if ((index == -1) || (index >= outPath.Length - 1))
                {
                    MessageBox.Show("输出文件路径有误!");
                    start = false;
                    return start;
                }
                else
                {
                    string outFilePath = outPath.Remove(index);
                    if (!(Directory.Exists(outFilePath)))
                    {
                        MessageBox.Show("输出文件路径有误!");
                        start = false;
                        return start;
                    }
                }
            }          

            return start;
        }
        private void Cancel_Click(object sender, EventArgs e)
        {
            progress = false;
            this.Close();
        }


        private void pictureBox1_Click(object sender, EventArgs e)
        {
            openFileDialog1.FileName = null;//清楚文件路径,防止再次导入时,取消后依然导入
            openFileDialog1.Filter = "Shapefile(*.shp)|*.shp";
            openFileDialog1.ShowDialog();
         
            this.textBox1.Text=openFileDialog1.FileName;
            if (textBox1.Text != "")
            { 
                AddComboBox1();
                this.textBox3.Text = this.textBox1.Text.Replace(".shp", "_voronoi.shp");
            }
        }
        [STAThread]
        private void mainThreadProcess()
        {
            //try
            {
                pProcess.run(textBox1.Text, textBox3.Text, classField, cellSize);
            }
            //catch (Exception ex)
            //{


            //    MessageBox.Show(ex.Message);


            //}
        }
        #region 进度条
        public void DoWork(object sender, DoWorkEventArgs e)
        {
            e.Result = ComputeFibonacci(worker, e);//当ComputeFibonacci(worker, e)返回时,异步过程结束
        }
        //调用 ReportProgress 时发生
        public void ProgessChanged(object sender, ProgressChangedEventArgs e)
        {
            this.toolStripProgressBar1.Value = e.ProgressPercentage;


            this.toolStripStatusLabel2.Text = Convert.ToString(e.ProgressPercentage);
        }
        //当后台操作已完成、被取消或引发异常时发生
        public void CompleteWork(object sender, RunWorkerCompletedEventArgs e)
        {
            MessageBox.Show("Complete!");
            this.Close();
            
        }


        private int ComputeFibonacci(object sender, DoWorkEventArgs e)
        {
            int i = 0;
            while (mainThread.IsAlive)
            {
                if (progress == false)
                {
                    MessageBox.Show("Cancelled!");
                    mainThread.Abort();//叫停处理图像进程              
                    System.Threading.Thread.CurrentThread.Abort();
                    
                }
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                }
                else
                {
                    worker.ReportProgress(i);
                }
                System.Threading.Thread.Sleep(300);
                i++; if (i == 100) i = 0;
            }
            worker.ReportProgress(100);
            return -1;


        }
        #endregion


        private void CalculateStatisticsFrom_FormClosed(object sender, FormClosedEventArgs e)
        {
            progress = false;
        }   
      
        private void AddComboBox1()
        {
            comboBox1.Items.Clear();
            ArrayList pValue = new ArrayList();
            pValue = pProcess.getZoneField(textBox1.Text);
            for (int i = 0; i < pValue.Count; i++)
            {
                comboBox1.Items.Add(pValue[i]);
            }
            comboBox1.Text = Convert.ToString(comboBox1.Items[3]);
        }
        private void pictureBox3_Click(object sender, EventArgs e)
        {
            saveFileDialog1.FileName = null;//清楚文件路径,防止再次导入时,取消后依然导入
            saveFileDialog1.Filter = "Shapefile(*.shp)|*.shp";
            saveFileDialog1.ShowDialog();
            this.textBox3.Text = saveFileDialog1.FileName;
        }                 
    }
}

 



这篇关于C#任意图形加权Voronoi图生成的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程