链式编码又称费尔曼编码或边界编码。链式编码将线状地物或区域边界表示为由某一起始点和在某些基本方向上的单位矢量链组成。单位矢量的长度为一个栅格单元,每个后继点可能位于其前继点的8个基本方向之一,存储的过程需要记录对象是多边形还是线性,记录线或多边形的起始行列号,并记录下每个对象的走向。
存储一个256*256的栅格数据,先绘制一条垂直线,一个矩形框,线和矩形框的颜色为红色
算法实现:
1)存储数据(线和面的不同是面需要有填充色)
①记录下线和面的走向,默认全部按顺时针处理
②记录下特征码:多边形还是线,线=2
③记录下起始点的行列号
④记录链码
⑤记录栅格值
2)按照不同的特征码读取数据并绘制,线和面的不同是:面需要填充内部
当依据一定的要求给定单位网格后,而网格中有多种地物类型(或说属性)时,则根据需要采取如下方案之一决定栅格单元的代码。
⑴ 中心点法:即用处于栅格中心处的地物类型(属性或量值或属性记录指针)或现象特征决定该栅格单元的代码。对于具有连续分布特征的地理要素,如降水分布、人口密度等问题,中心法是被首要选用的。
⑵ 面积占优法:以占矩形面积最大的地物或现象特性的重要性决定栅格单元的代码,此法常见于分类较细,地物类别斑块较小的情况。
⑶ 长度占优法:当覆盖的栅格过中心位置时,横线占据该格中的大部分长度的属性值定为该栅格单元的代码。
⑷ 重要性法:根据栅格内不同地物的重要性,选取最重要的地物类型决定相应的栅格单元代码。此法常见于具有特殊意义而面积较小且不在栅格中心的地理要素。尤其是点、线状地理要素,如城镇、交通枢纽、交通线、河流水系等。
以上4点正确使用,则能较好地保持地表的真实性,尽可能地保持原图或原始数据的精度问题。当然,缩小单个栅格单元面积,使每个栅格单元代表更为精细的地面矩形单元,减少混合单元、混合类型与混合面积,可大大提高量算精度,保持真实形态及更细小的地物类型。但增加栅格个数会使数据多,冗余严重。为解决此问题,产生了一系列各具特色的栅格数据压缩编码方法。
看下链式编码中的面!
面的边框生成算法与线的生成算法一样,但面需要填充而线不需要填充,经典的填充算法有:通用扫描线填充算法和边界填充算法
边界填充算法:假如边界是以单一颜色指定的,则填充算法可逐个像素地向外处理,直至遇到边界颜色。这种方法称为边界填充算法。基本上,边界填充算法从一个内点(x,y)开始检测相邻位置的颜色。如果检测位置不是该边界线颜色,就将它改为填充颜色,并再次检测其相邻位置。这个过程延续到检测完区域边界颜色范围内的所有像素为止
通用扫描线填充算法:要实现区域的扫描线填充,必须先确定填充区边界与屏幕扫描线的交点位置。然后,将填充色应用于扫描线上位于填充区内部的每一段。扫描线填充算法利用奇偶规则识别同一内部区域。
这里我们采用通用扫描线填充算法,进行了一下改良,处理流程:
1)存储多边形的链码信息,与上次说的线存储类似
2)根据链码信息生成多边形的边框,与上次说的线框生成类似
3)填充:为了缩小判断范围(即哪些栅格需要上色),可以根据多边形的边界求出最小外接矩形,然后再该矩形内部判断即可
4)从最小外接矩形最上方做平行于x的线段,即y=Ymin,
5)求出y=Ymin与多边形边界的交点坐标,只考虑凸多边形
6)则对于y=Ymin这一行,交点之间的部分为多边形内部的栅格像元,需要填充颜色
7)依照此法遍历完Ymin~Ymax之间的所有行即可填充完成
存储链码,这串链码表示多边形
读取链码并显示,需要根据上次线链码的基础上获取最小点xy坐标和最大点xy坐标,并求出与边界的交点(这里只要用getpixel即可求出交点),填充多边形颜色
我们以这个为例
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 验证码
{
public partial class Form7 : Form
{
public Form7()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string strtemp = "";
if (!File.Exists("d:\\data\\lianshiraster.txt"))
{
FileStream fs1 = new FileStream("d:\\data\\lianshiraster.txt", FileMode.Create, FileAccess.Write);//创建写入文件
StreamWriter sw = new StreamWriter(fs1);
strtemp = "2|0,4|1,1,2,2,4,4,4,4,6,6,4,2,2|R";
sw.WriteLine(strtemp);
strtemp = "3 | 5,2 | 6,2,2,4,6,6,4,2,2,4,6 | R";
sw.WriteLine(strtemp);
sw.Close();
fs1.Close();
}
else
{
FileStream fs = new FileStream("d:\\data\\lianshiraster.txt", FileMode.Open, FileAccess.Write);
StreamWriter sr = new StreamWriter(fs);
strtemp = "2|0,4|1,1,2,2,4,4,4,4,6,6,4,2,2|R";
sr.WriteLine(strtemp);
strtemp = "3|10,2|6,2,2,4,6,6,4,2,2,4,6|R";
sr.WriteLine(strtemp);
sr.Close();
fs.Close();
}
}
private void button2_Click(object sender, EventArgs e)
{
Bitmap image = new Bitmap(16, 16);//初始化大小
//读取txt文件并绘制图片
string filePath = "d:\\data\\lianshiraster.txt";
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
string str = sr.ReadLine();//开始读入值
int i = 0;
while (str != null)
{
string[] strtemp1 = str.Split('|');
int m = 0;
if (strtemp1[0] == "2")
{
string[] str2 = strtemp1[1].Split(',');
if (strtemp1[3].ToString() == "R")
{
image.SetPixel(Convert.ToInt32(str2[0]), Convert.ToInt32(str2[1]), Color.Red);
string[] str3 = strtemp1[2].Split(',');
int currentX = 0;
int currentY = 4;
for (int j = 0; j < str3.Length; j++)
{
switch (str3[j])
{
case "0":
currentY = currentY - 1;
image.SetPixel(currentX, currentY, Color.Red);
break;
case "1":
currentX = currentX + 1;
currentY = currentY - 1;
image.SetPixel(currentX, currentY, Color.Red);
break;
case "2":
currentX = currentX + 1;
image.SetPixel(currentX, currentY, Color.Red);
break;
case "3":
currentX = currentX + 1;
currentY = currentY + 1;
image.SetPixel(currentX, currentY, Color.Red);
break;
case "4":
currentY = currentY + 1;
image.SetPixel(currentX, currentY, Color.Red);
break;
case "5":
currentX = currentX - 1;
currentY = currentY + 1;
image.SetPixel(currentX, currentY, Color.Red);
break;
case "6":
currentX = currentX - 1;
image.SetPixel(currentX, currentY, Color.Red);
break;
case "7":
currentX = currentX - 1;
currentY = currentY - 1;
image.SetPixel(currentX, currentY, Color.Red);
break;
default:
break;
}
}
}
else
{
}
}
else
{
int Xmin;
int Ymin;
int Xmax;
int Ymax;
string[] str4 = strtemp1[1].Split(',');
if (strtemp1[3].ToString() == "R")
{
image.SetPixel(Convert.ToInt32(str4[0]), Convert.ToInt32(str4[1]), Color.Red);
string[] str5 = strtemp1[2].Split(',');
string[] str6 = strtemp1[1].Split(',');
int currentX = Convert.ToInt32(str6[0]);
int currentY = Convert.ToInt32(str6[1]);
Xmin = currentX;
Ymin = currentY;
Xmax = currentX;
Ymax = currentY;
for (int j = 0; j < str5.Length; j++)
{
switch (str5[j])
{
case "0":
currentY = currentY - 1;
image.SetPixel(currentX, currentY, Color.Red);
if (currentX > Xmax)
{
Xmax = currentX;
}
if (currentX < Xmin)
{
Xmin = currentX;
}
if (currentY > Ymax)
{
Ymax = currentY;
}
if (currentY < Ymin)
{
Ymin = currentY;
}
break;
case "1":
currentX = currentX + 1;
currentY = currentY - 1;
image.SetPixel(currentX, currentY, Color.Red);
if (currentX > Xmax)
{
Xmax = currentX;
}
if (currentX < Xmin)
{
Xmin = currentX;
}
if (currentY > Ymax)
{
Ymax = currentY;
}
if (currentY < Ymin)
{
Ymin = currentY;
}
break;
case "2":
currentX = currentX + 1;
image.SetPixel(currentX, currentY, Color.Red);
if (currentX > Xmax)
{
Xmax = currentX;
}
if (currentX < Xmin)
{
Xmin = currentX;
}
if (currentY > Ymax)
{
Ymax = currentY;
}
if (currentY < Ymin)
{
Ymin = currentY;
}
break;
case "3":
currentX = currentX + 1;
currentY = currentY + 1;
image.SetPixel(currentX, currentY, Color.Red);
if (currentX > Xmax)
{
Xmax = currentX;
}
if (currentX < Xmin)
{
Xmin = currentX;
}
if (currentY > Ymax)
{
Ymax = currentY;
}
if (currentY < Ymin)
{
Ymin = currentY;
}
break;
case "4":
currentY = currentY + 1;
image.SetPixel(currentX, currentY, Color.Red);
if (currentX > Xmax)
{
Xmax = currentX;
}
if (currentX < Xmin)
{
Xmin = currentX;
}
if (currentY > Ymax)
{
Ymax = currentY;
}
if (currentY < Ymin)
{
Ymin = currentY;
}
break;
case "5":
currentX = currentX - 1;
currentY = currentY + 1;
image.SetPixel(currentX, currentY, Color.Red);
if (currentX > Xmax)
{
Xmax = currentX;
}
if (currentX < Xmin)
{
Xmin = currentX;
}
if (currentY > Ymax)
{
Ymax = currentY;
}
if (currentY < Ymin)
{
Ymin = currentY;
}
break;
case "6":
currentX = currentX - 1;
image.SetPixel(currentX, currentY, Color.Red);
if (currentX > Xmax)
{
Xmax = currentX;
}
if (currentX < Xmin)
{
Xmin = currentX;
}
if (currentY > Ymax)
{
Ymax = currentY;
}
if (currentY < Ymin)
{
Ymin = currentY;
}
break;
case "7":
currentX = currentX - 1;
currentY = currentY - 1;
image.SetPixel(currentX, currentY, Color.Red);
if (currentX > Xmax)
{
Xmax = currentX;
}
if (currentX < Xmin)
{
Xmin = currentX;
}
if (currentY > Ymax)
{
Ymax = currentY;
}
if (currentY < Ymin)
{
Ymin = currentY;
}
break;
default:
break;
}
}
//得到交点坐标
for (int n = Ymin; n < Ymax + 1; n++)
{
for (m = Xmin; m < Xmax + 1; m++)
{
if (image.GetPixel(m, n).ToArgb() == Color.Red.ToArgb())
{
for (int k = m + 1; k < Xmax; k++)
{
if (image.GetPixel(k, n) == Color.Red)
{
break;
}
else
{
image.SetPixel(k, n, Color.Red);
}
}
break;
}
}
}
}
else
{
}
}
str = sr.ReadLine();
// i = i + 1;
}
Graphics g = Graphics.FromImage(image);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;//设置图片质量
g.DrawImage(image, 0, 0, 16, 16);//设置位置
image.Save("d:\\data\\" + "lianshiraster222.jpg");//自己创建一个文件夹,放入生成的图片(根目录下)
}
private void Form7_Load(object sender, EventArgs e)
{
}
}
}
效果图如下