12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Forms;
- using OpenCvSharp;
- namespace ceju
- {
- class SubFunction
- {
- /*
- * 摘要:
- * 计算图片非零像素的平均阈值
- * 参数:
- * image:
- * 输入图片,(单通道)
- * threshold:
- * 输出阈值
- */
- public static void AverageThreshold(Mat image, out double threshould)
- {
- // 计算非零像素的个数
- int count = 0;
- BasFunction.Count(image, out count);
- // 计算像素和
- double sum = 0;
- for (int i = 0; i < image.Rows; i++)
- {
- for (int j = 0; j < image.Cols; j++)
- {
- sum += image.Get<int>(i, j);
- }
- }
- // 求平均阈值
- threshould = sum / count;
- }
- /*
- * 摘要:
- * 提取图像的中部区域的边界
- * 参数:
- * image:
- * 阈值分割后的二值0,1图像
- * 返回:
- * 数组middleArea;
- * middleArea[0]:中部左边界
- * middleArea[1]:中部右边界
- * 方法:
- * 对每列求和,得到行向量;
- * 得到行向量的最大值;
- * 分别对行向量从左往右和从右往左遍历,找到大于最大值-10的列
- */
- public static int[] GetMiddleArea(Mat image)
- {
- //求行数和列数
- int rows = image.Rows;
- int cols = image.Cols;
- //将Mat类中的数据放到数组中
- int[,] arr = BasFunction.Mat2Array(image);
- //将数组转换成0,1数组
- arr = BasFunction.ConversionRange(arr);
- //中部边界的数组
- int[] middleArea = new int[2];
- //对数组每列求和得到行向量
- int[] sumC = BasFunction.Sum(arr, 1);
- //得到该行向量的最大值
- int sumCMax = BasFunction.Max(sumC);
- //从左向右遍历,大于临界值时,得到中部左边界
- for (int j = 0; j < cols; j++)
- {
- if (sumC[j] > sumCMax - 10)
- {
- middleArea[0] = j;
- break;
- }
- }
- //从右向左遍历,大于临界值时,得到中部右边界
- for (int j = cols - 1; j >= 0; j--)
- {
- if (sumC[j] > sumCMax - 10)
- {
- middleArea[1] = j;
- break;
- }
- }
- return middleArea;
- }
- /*
- * 摘要:
- * 得到数据提取区域的边界
- * 参数:
- * image:
- * 输入阈值分割后的图像
- * middleArea:
- * 输入中间区域的边界,
- * middleArea[0]:中部左边界
- * middleArea[1]:中部右边界
- * 返回:
- * dataArea:
- * 数据提取区域的边界
- * dataArea[0]:左半边的左边界
- * dataArea[1]:左半边的右边界
- * dataArea[2]:右半边的左边界
- * dataArea[3]:右半边的右边界
- */
- public static int[] GetDataArea(Mat image, int[] middleArea)
- {
- //图片行列数
- int rows = image.Rows;
- int cols = image.Cols;
- //图片填充的上界
- int y = 0;
- //将Mat类数据存入数组中
- int[,] arr = BasFunction.Mat2Array(image);
- //将数组转换成0,1数组
- arr = BasFunction.ConversionRange(arr);
- //对二维数组每行求和,输出列向量
- int[] sumR = BasFunction.Sum(arr, 2);
- //列向量的最大值
- int sumRMax = BasFunction.Max(sumR);
- //当列向量某行的值大于最大值的一半时,得到填充上界
- for (int i = 1; i < rows; i++)
- {
- if (sumR[i] > sumRMax / 2)
- {
- y = i;
- break;
- }
- }
- //将二维数组,y以下的所有行都变为1
- int[,] arrFill = arr;
- for (int i = y; i < rows; i++)
- {
- for (int j = 1; j < cols; j++)
- {
- arrFill[i, j] = 1;
- }
- }
- //对填充后的数组每列求和,得到行向量
- int[] sumCArrayFill = BasFunction.Sum(arrFill, 1);
- //该行向量的middleArea[0] - 500到middleArea[0]区间,左半边
- int[] sumCArrayFillLeft = BasFunction.Intercept(sumCArrayFill, middleArea[0] - 500, middleArea[0]);
- //该行向量的middleArea[1]到middleArea[1] + 500区间,右半边
- int[] sumCArrayFillRight = BasFunction.Intercept(sumCArrayFill, middleArea[1], middleArea[1] + 500);
- //左半边的最大值
- int sumCArrayFillLeftMax = BasFunction.Max(sumCArrayFillLeft);
- //右半边最大值
- int sumCArrayFillRightMax = BasFunction.Max(sumCArrayFillRight);
- //数据提取区域,分别是左半边左右边界,右半边左右边界
- int[] dataArea = new int[4];
- for (int j = middleArea[0] - 500; j < middleArea[0]; j++)
- {
- if (sumCArrayFill[j] > sumCArrayFillLeftMax - 10)
- {
- dataArea[0] = j;
- break;
- }
- }
- for (int j = middleArea[0]; j > middleArea[0] - 500; j--)
- {
- if (sumCArrayFill[j] > sumCArrayFillLeftMax - 5)
- {
- dataArea[1] = j;
- break;
- }
- }
- for (int j = middleArea[1]; j < middleArea[1] + 500; j++)
- {
- if (sumCArrayFill[j] > sumCArrayFillRightMax - 5)
- {
- dataArea[2] = j;
- break;
- }
- }
- for (int j = middleArea[1] + 500; j > middleArea[1]; j--)
- {
- if (sumCArrayFill[j] > sumCArrayFillRightMax - 10)
- {
- dataArea[3] = j;
- break;
- }
- }
- return dataArea;
- }
- /*
- * 摘要:
- * 提取线条,保存每列第一个点,需要没有间断点
- * 参数:
- * array:
- * 输入二维数组,0,1二值
- * line:
- * 输出线条,0,1二值
- * averageCoordinate:
- * 输出平均纵坐标
- * leftBorder:
- * 左边界
- * rightBorder:
- * 右边界
- */
- public static void ExtractLines(int[,] array, out int[,] line, out double averageCoordinate, int leftBorder, int rightBorder)
- {
- //数组长宽
- int rows = array.GetLength(0);
- int cols = array.GetLength(1);
- //输出的线条数组
- line = new int[rows, cols];
- //记录线条上点的纵坐标数组
- int[] coordinate = new int[cols];
- //线条平均纵坐标
- averageCoordinate = 0;
- //纵坐标之和
- int sum = 0;
- //线条上点的个数
- int count = 0;
- //遍历,原数组上该位置有点时,线条上的该位置置1
- for (int j = leftBorder; j < rightBorder; j++)
- {
- for (int i = 0; i < rows; i++)
- {
- if (array[i, j] == 1)
- {
- line[i, j] = 1;
- coordinate[j] = i;
- break;
- }
- }
- }
- //计算纵坐标之和
- BasFunction.Sum(coordinate, out sum);
- //计算线条内点的个数
- BasFunction.Count(coordinate, out count);
- //平均纵坐标
- averageCoordinate = sum / count;
- }
- /*
- * 摘要:
- * 提取线条,保存每列第一个点,需要没有间断点,不输出线条
- * 参数:
- * array:
- * 输入二维数组,0,1二值
- * averageCoordinate:
- * 输出平均纵坐标
- * leftBorder:
- * 左边界
- * rightBorder:
- * 右边界
- */
- public static void ExtractLines(int[,] array, out double averageCoordinate, int leftBorder, int rightBorder)
- {
- //数组长宽
- int rows = array.GetLength(0);
- int cols = array.GetLength(1);
- //记录线条上点的纵坐标数组
- int[] coordinate = new int[cols];
- //线条平均纵坐标
- averageCoordinate = 0;
- //纵坐标之和
- int sum = 0;
- //线条上点的个数
- int count = 0;
- //遍历,查询有点的个数
- for (int j = leftBorder; j < rightBorder; j++)
- {
- for (int i = 0; i < rows; i++)
- {
- if (array[i, j] == 1)
- {
- coordinate[j] = i;
- break;
- }
- }
- }
- //计算纵坐标之和
- BasFunction.Sum(coordinate, out sum);
- //计算线条内点的个数
- BasFunction.Count(coordinate, out count);
- //平均纵坐标
- averageCoordinate = sum / count;
- }
- /*
- * 摘要:
- * 提取线条,保存每列第一个点,需要没有间断点
- * 参数:
- * array:
- * 输入二维数组,0,1二值
- * line:
- * 输出线条,0,1二值
- * averageCoordinateNew:
- * 输出平均纵坐标
- * leftBorder:
- * 左边界
- * rightBorder:
- * 右边界
- * averageCoordinate:
- * 作为基准的上一条线的平均纵坐标
- */
- public static void ExtractLines(int[,] array, out int[,] line, out double averageCoordinateNew, int leftBorder, int rightBorder, double averageCoordinate)
- {
- //数组长宽
- int rows = array.GetLength(0);
- int cols = array.GetLength(1);
- //输出的线条数组
- line = new int[rows, cols];
- //新的记录线条纵坐标的数组
- int[] coordinateNew = new int[cols];
- //遍历范围的上界和下界
- int upperBound = (int)averageCoordinate + 15;
- int lowerBound = (int)averageCoordinate + 45;
- //初始化,记录纵坐标的数组全为0
- for (int j = 0; j < cols; j++)
- {
- coordinateNew[j] = 0;
- }
- //计算线条内点的个数
- int count = 0;
- BasFunction.Count(coordinateNew, out count);
- //当点的个数少于5的时候循环
- while (count < 5)
- {
- //每次循环,寻找范围向下移动5个像素
- upperBound = upperBound + 5;
- lowerBound = lowerBound + 5;
- //遍历,寻找线条上的点,并记录纵坐标
- for (int j = leftBorder; j < rightBorder; j++)
- {
- for (int i = upperBound; i < lowerBound; i++)
- {
- if (array[i, j] > 0)
- {
- line[i, j] = 1;
- coordinateNew[j] = i;
- break;
- }
- }
- }
- //重新计算线条内点的个数
- BasFunction.Count(coordinateNew, out count);
- }
- //纵坐标之和
- int sum = 0;
- BasFunction.Sum(coordinateNew, out sum);
- //平均纵坐标
- averageCoordinateNew = 0;
- averageCoordinateNew = sum / count;
- }
- /*
- * 摘要:
- * 提取线条,保存每列第一个点,需要没有间断点,不输出线条,只输出纵坐标
- * 参数:
- * array:
- * 输入二维数组,0,1二值
- * averageCoordinateNew:
- * 输出平均纵坐标
- * leftBorder:
- * 左边界
- * rightBorder:
- * 右边界
- * averageCoordinate:
- * 作为基准的上一条线的平均纵坐标
- */
- public static void ExtractLines(int[,] array, out double averageCoordinateNew, int leftBorder, int rightBorder, double averageCoordinate)
- {
- //数组长宽
- int rows = array.GetLength(0);
- int cols = array.GetLength(1);
- //新的记录线条纵坐标的数组
- int[] coordinateNew = new int[cols];
- //遍历范围的上界和下界
- int upperBound = (int)averageCoordinate + 15;
- int lowerBound = (int)averageCoordinate + 45;
- //初始化,记录纵坐标的数组全为0
- for (int j = 0; j < cols; j++)
- {
- coordinateNew[j] = 0;
- }
- //计算线条内点的个数
- int count = 0;
- BasFunction.Count(coordinateNew, out count);
- //当点的个数少于5的时候循环
- while (count < 5)
- {
- //每次循环,寻找范围向下移动5个像素
- upperBound = upperBound + 5;
- lowerBound = lowerBound + 5;
- //遍历,寻找线条上的点,并记录纵坐标
- for (int j = leftBorder; j < rightBorder; j++)
- {
- for (int i = upperBound; i < lowerBound; i++)
- {
- if (array[i, j] > 0)
- {
- coordinateNew[j] = i;
- break;
- }
- }
- }
- //重新计算线条内点的个数
- BasFunction.Count(coordinateNew, out count);
- }
- //纵坐标之和
- int sum = 0;
- BasFunction.Sum(coordinateNew, out sum);
- //平均纵坐标
- averageCoordinateNew = 0;
- averageCoordinateNew = sum / count;
- }
- /*
- * 摘要:
- * 提取线条,保存每列第一个点,需要没有间断点,不输出线条,只输出纵坐标(从下往上)
- * 参数:
- * array:
- * 输入二维数组,0,1二值
- * averageCoordinateNew:
- * 输出平均纵坐标
- * leftBorder:
- * 左边界
- * rightBorder:
- * 右边界
- * averageCoordinate:
- * 作为基准的上一条线的平均纵坐标
- */
- public static void ExtractLines2(int[,] array, out double averageCoordinateNew, int leftBorder, int rightBorder, double averageCoordinate)
- {
- //数组长宽
- int rows = array.GetLength(0);
- int cols = array.GetLength(1);
- //新的记录线条纵坐标的数组
- int[] coordinateNew = new int[cols];
- //遍历范围的上界和下界
- int upperBound = (int)averageCoordinate - 45;
- int lowerBound = (int)averageCoordinate - 10;
- //初始化,记录纵坐标的数组全为0
- for (int j = 0; j < cols; j++)
- {
- coordinateNew[j] = 0;
- }
- //计算线条内点的个数
- int count = 0;
- BasFunction.Count(coordinateNew, out count);
- //当点的个数少于5的时候循环
- while (count < 5)
- {
- //每次循环,寻找范围向下移动5个像素
- upperBound = upperBound - 5;
- lowerBound = lowerBound - 5;
- //遍历,寻找线条上的点,并记录纵坐标
- for (int j = leftBorder; j < rightBorder; j++)
- {
- for (int i = lowerBound; i > upperBound; i--)
- {
- if (array[i, j] > 0)
- {
- coordinateNew[j] = i;
- break;
- }
- }
- }
- //重新计算线条内点的个数
- BasFunction.Count(coordinateNew, out count);
- }
- //纵坐标之和
- int sum = 0;
- BasFunction.Sum(coordinateNew, out sum);
- //平均纵坐标
- averageCoordinateNew = 0;
- averageCoordinateNew = sum / count;
- }
- /*
- * 摘要:
- * 计算孔径的起止点
- * 参数:
- * array:
- * 阈值分割后的目标区域数组
- * aperture:
- * 输出孔径起止点
- * aperture[0]:左起始点
- * aperture[1]:右结束点
- * ordinate1:
- * 左部分纵坐标
- * ordinate2:
- * 右部分纵坐标
- * middleArea:
- * 中部区域边界
- * middleArea[0]:中部左边界
- * middleArea[1]:中部右边界
- * dataArea:
- * 数据提取区域边界
- * dataArea[0]:左部分左边界
- * dataArea[1]:左部分右边界
- * dataArea[2]:右部分左边界
- * dataArea[3]:右部分右边界
- */
- public static void GetAperture(int[,] array, out int[] aperture, int ordinate1, int ordinate2, int[] middleArea, int[] dataArea)
- {
- //孔径起始点
- aperture = new int[2];
- //数组行列数
- int rows = array.GetLength(0);
- int cols = array.GetLength(1);
- //中部区域的中心
- int middle = (middleArea[0] + middleArea[1]) / 2;
- //左右截取的区域
- int[,] leftSeg = new int[rows, cols];
- int[,] rightSeg = new int[rows, cols];
- leftSeg = BasFunction.InterceptArray(array, leftSeg, ordinate1 - 10, ordinate1 + 10, dataArea[0], middleArea[0] + 5, 1);
- rightSeg = BasFunction.InterceptArray(array, rightSeg, ordinate2 - 10, ordinate2 + 10, middleArea[1] - 5, dataArea[3], 1);
- //左部分列求和,行向量
- int[] sum1 = BasFunction.Sum(leftSeg, 1);
- //右部分列求和,行向量
- int[] sum2 = BasFunction.Sum(rightSeg, 1);
- //左部分遍历,从中间到左边界,当大于0时记录为孔径起始点
- for (int j = middle; j > dataArea[0]; j--)
- {
- if (sum1[j] > 0)
- {
- aperture[0] = j;
- break;
- }
- }
- //右部分遍历,从中间到右边界,当大于0时记录为孔径结束点
- for (int j = middle; j < dataArea[3]; j++)
- {
- if (sum2[j] > 0)
- {
- aperture[1] = j;
- break;
- }
- }
- }
- /*
- * 摘要:
- * 计算孔铜距离并得到对应的曲面上的点坐标
- * 参数:
- * line:
- * 第一条线
- * apertureBeign:
- * 孔径左起始点坐标,先纵坐标后横坐标
- * apertureEnd:
- * 孔径右截止点坐标,先纵坐标后横坐标
- * kongtong:
- * 输出孔铜数据数组,先左后右
- * pointLeft:
- * 曲面上左面的点坐标,先纵坐标后横坐标
- * pointRight:
- * 曲面上右面的点坐标,先纵坐标后横坐标
- */
- public static void GetKongtong(int[,] line, int[] apertureBegin, int[] apertureEnd, out double[] kongtong, out int[] pointLeft, out int[] pointRight)
- {
- //数组行列数
- int rows = line.GetLength(0);
- int cols = line.GetLength(1);
- //截取曲面线条
- int[,] lineSeg = new int[rows, cols];
- lineSeg = BasFunction.InterceptArray(line, lineSeg, 0, rows, apertureBegin[1], apertureEnd[1]);
- //曲面上点的个数
- int count = 0;
- BasFunction.Count(lineSeg, out count);
- //得到曲面线条上点的坐标位置
- int[,] coordinate = new int[count, 2];
- BasFunction.Find(lineSeg, out coordinate);
- //计算距离,最小的距离分别为左孔铜和右孔铜
- double leftKongtong = 1000;
- double rightKongtong = 1000;
- double distance1 = 0;
- double distance2 = 0;
- //当距离最短是曲线上点的坐标,第一列是纵坐标(行数),第二列是横坐标(列数)
- pointLeft = new int[2];
- pointRight = new int[2];
- for (int i = 0; i < count; i++)
- {
- //计算曲面点到左起始点的距离
- distance1 = Math.Sqrt(Math.Pow((coordinate[i, 0] - apertureBegin[0]), 2) + Math.Pow((coordinate[i, 1] - apertureBegin[1]), 2));
- //计算曲面点到右截止点的距离
- distance2 = Math.Sqrt(Math.Pow((coordinate[i, 0] - apertureEnd[0]), 2) + Math.Pow((coordinate[i, 1] - apertureEnd[1]), 2));
- //得到左右孔铜以及对应的曲面坐标
- if (leftKongtong > distance1)
- {
- leftKongtong = distance1;
- pointLeft[0] = coordinate[i, 0];
- pointLeft[1] = coordinate[i, 1];
- }
- if (rightKongtong > distance2)
- {
- rightKongtong = distance2;
- pointRight[0] = coordinate[i, 0];
- pointRight[1] = coordinate[i, 1];
- }
- }
- kongtong = new double[2] { leftKongtong, rightKongtong };
- }
- /*
- * 摘要:
- * 得到孔深,并且得到曲面最凸点或者最凹点的坐标
- * 参数:
- * line:
- * 线条
- * apertureBegin:
- * 孔径左侧起始点坐标,先纵后横
- * apertureEnd:
- * 孔径右侧结束点坐标,先纵后横
- * curveVertex:
- * 曲面凸点的坐标
- */
- public static void CurveVertex(int[,] line, int[] apertureBegin, int[] apertureEnd, out int[] curveVertex, out double middleApertureY)
- {
- //曲面顶点的坐标
- curveVertex = new int[2];
- //数组行列数
- int rows = line.GetLength(0);
- int cols = line.GetLength(1);
- //孔径平均横坐标
- double middleAperture = (apertureBegin[1] + apertureEnd[1]) / 2;
- //孔径平均高度
- int[] apertureY = new int[2];
- for (int i = 0; i < rows; i++)
- {
- if (line[i, apertureBegin[1]] > 0)
- {
- apertureY[0] = i;
- break;
- }
- }
- for (int i = 0; i < rows; i++)
- {
- if (line[i, apertureEnd[1]] > 0)
- {
- apertureY[1] = i;
- break;
- }
- }
- middleApertureY = (apertureY[0] + apertureY[1]) / 2;
- //截取曲面线条
- int[,] lineSeg = new int[rows, cols];
- lineSeg = BasFunction.InterceptArray(line, lineSeg, 0, rows, apertureBegin[1], apertureEnd[1]);
- //曲面上点的个数
- int count = 0;
- BasFunction.Count(lineSeg, out count);
- //得到曲面线条上点的坐标位置
- int[,] coordinate = new int[count, 2];
- BasFunction.Find(lineSeg, out coordinate);
- //孔深,取曲面上的点到孔径平均高度只差的最大值
- double kongshenAomian = 0;
- double kongshenTumian = 0;
- int[] coordinateAomian = new int[2];
- int[] coordinateTumian = new int[2];
- double tAomian = 0;
- double tTumian = 0;
- for (int i = 0; i < count; i++)
- {
- tAomian = coordinate[i, 0] - middleApertureY;
- tTumian = middleApertureY - coordinate[i, 0];
- if (tAomian > kongshenAomian)
- {
- kongshenAomian = tAomian;
- //纵坐标
- coordinateAomian[0] = coordinate[i, 0];
- //横坐标
- coordinateAomian[1] = coordinate[i, 1];
- }
- if (tTumian > kongshenTumian)
- {
- kongshenTumian = tTumian;
- coordinateTumian[0] = coordinate[i, 0];
- coordinateTumian[1] = coordinate[i, 1];
- }
- }
- //判断哪个点离孔径中心更近,更近的为曲面坐标
- double absAomian = Math.Abs(coordinateAomian[1] - middleAperture);
- double absTumian = Math.Abs(coordinateTumian[1] - middleAperture);
- if (absAomian < absTumian)
- {
- curveVertex = coordinateAomian;
- }
- else
- {
- curveVertex = coordinateTumian;
- }
- }
- /*
- * 摘要:
- * 得到内部线条,将内部线条进行腐蚀后,求平均纵坐标
- * 参数:
- * image:
- * 输入图像,一般是绿色通道
- * upperBound, lowerBound, leftBoundary, rightBoundary:
- * 内部区域的上下左右边界
- * meanOrdinate:
- * 输出的纵坐标
- *
- */
- public static void InsideLine(Mat image, int upperBound, int lowerBound, int leftBoundary, int rightBoundary, out double meanOrdinate)
- {
- // 内部区域的行列数
- int rows = lowerBound - upperBound;
- int cols = rightBoundary - leftBoundary;
- // 内部区域的图像
- Mat inside = new Mat(rows, cols, image.Type());
- // 滤波提高对比度后的图像
- Mat filter = new Mat(rows, cols, MatType.CV_8UC1);
- // 绘制内部区域像素
- for (int i = 0; i < rows; i++)
- {
- for (int j = 0; j < cols; j++)
- {
- int value = image.Get<int>(i + upperBound, j + leftBoundary);
- inside.Set<int>(i, j, 255 - value);
- }
- }
- // 滤波核
- InputArray kernel = InputArray.Create<int>(new int[3, 3] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } });
- // 滤波
- Cv2.Filter2D(inside, filter, -1, kernel);
- Cv2.ConvertScaleAbs(filter, filter);
- // 腐蚀宽度
- double width = (rightBoundary - leftBoundary) * 0.3;
- // 腐蚀结构元素
- Mat seErode = Cv2.GetStructuringElement(MorphShapes.Rect, new Size((int)width, 1));
- // 腐蚀
- Mat erode = new Mat();
- //Cv2.Erode(filter, erode, seErode);
- // 二值化
- Mat thresh = new Mat(filter.Size(), filter.Type());
- thresh = filter.Threshold(0, 255, ThresholdTypes.Otsu);
- // 再次腐蚀
- Cv2.Erode(thresh, erode, seErode);
- // 边缘检测
- Mat grad_y = new Mat();
- Mat grad_y2 = new Mat();
- Cv2.Sobel(erode, grad_y, MatType.CV_16S, 0, 1);
- Cv2.ConvertScaleAbs(grad_y, grad_y2);
- //new Window("zengqiang", WindowMode.Normal, filter);
- //new Window("erzhihua", WindowMode.Normal, thresh);
- //new Window("fushi", WindowMode.Normal, erode);
- //new Window("bianyuanjiance", WindowMode.Normal, grad_y2);
- //Cv2.WaitKey(0);
- int[,] arraySobel = new int[rows, cols];
- arraySobel = BasFunction.Mat2Array(grad_y2);
- arraySobel = BasFunction.ConversionRange(arraySobel);
- int[,] line6 = new int[rows, cols];
- meanOrdinate = 0;
- //SubFunction.ExtractLines(arraySobel, out line6, out meanOrdinateL6, 0, 180,1);
- //meanOrdinateL6 = meanOrdinateL6-3 + upperBound;
- // 非零元素坐标
- int[,] coordianate;
- BasFunction.Find(arraySobel, out coordianate);
- // 非零元素个数
- int count = coordianate.GetLength(0);
- double sum = 0;
- for (int i = 0; i < count; i++)
- {
- sum += coordianate[i, 0];
- }
- // 得到内部线的纵坐标(平均坐标加上上界)
- meanOrdinate = sum / count + upperBound;
- //new Window("inside", WindowMode.AutoSize, inside);
- //new Window("filter", WindowMode.AutoSize, filter);
- //new Window("thresh", WindowMode.AutoSize, thresh);
- //new Window("sobel", WindowMode.AutoSize, grad_y2);
- //Cv2.WaitKey(0);
- }
- public static double AverageBrightness(double[,] array)
- {
- //数组中大于0的个数
- int count = 0;
- BasFunction.Count(array, out count);
- //数组中所有亮度之和
- double sum = 0;
- BasFunction.Sum(array, out sum);
- //数组中的平均亮度
- double result = sum / count;
- return result;
- }
- /*
- * 摘要:
- * 绘制线条
- * 参数:
- * image:
- * 绘制的图片
- * x1:点1的横坐标
- * y1:点1的纵坐标
- * x2:点2的横坐标
- * y2:点2的纵坐标
- */
- public static void LineShow(Mat image, int x1, int y1, int x2, int y2)
- {
- Point p1 = new Point();
- Point p2 = new Point();
- p1.X = x1;
- p1.Y = y1;
- p2.X = x2;
- p2.Y = y2;
- Scalar color = new Scalar(0, 0, 255);
- //颜色
- Cv2.Line(image, p1, p2, color, 2, LineTypes.Link8);
- }
- /*
- * 摘要:
- * 将三通道图片分割成单通道
- * 参数:
- * image:
- * 三通道图片
- * imageBlue,imageGreen,imageRed:
- * 蓝绿红图片
- * colorChoose:
- * 选择线条颜色,blue,green,red
- */
- public static void LineShow(Mat image, int x1, int y1, int x2, int y2, string colorChoose)
- {
- Point p1 = new Point();
- Point p2 = new Point();
- p1.X = x1;
- p1.Y = y1;
- p2.X = x2;
- p2.Y = y2;
- Scalar color = new Scalar();//颜色
- switch (colorChoose)
- {
- case "blue":
- color = new Scalar(255, 0, 0);
- break;
- case "green":
- color = new Scalar(0, 255, 0);
- break;
- case "red":
- color = new Scalar(0, 0, 255);
- break;
- default:
- break;
- }
- Cv2.Line(image, p1, p2, color, 2, LineTypes.Link8);
- }
- /*
- * 摘要:
- * 显示文字
- * 参数:
- * image:
- * 背景图片
- * data:
- * 显示数字
- * x,y:
- * 显示坐标
- */
- public static void TextShow(Mat image, double data, int x, int y)
- {
- data = Math.Round(data, 2);
- Scalar color = new Scalar(255, 0, 0);
- Point p = new Point();
- p.X = x;
- p.Y = y;
- Cv2.PutText(image, data.ToString() + "um", p, HersheyFonts.HersheyComplex, 0.8, color, 2, LineTypes.Link8);
- }
- /*
- * 摘要:
- * 将三通道图片分割成单通道
- * 参数:
- * image:
- * 三通道图片
- * imageBlue,imageGreen,imageRed:
- * 蓝绿红图片
- */
- public static void SeparateRGB(Mat image, out Mat imageBlue, out Mat imageGreen, out Mat imageRed)
- {
- int rows = image.Rows;
- int cols = image.Cols;
- imageBlue = new Mat(rows, cols, MatType.CV_8UC1);
- imageGreen = new Mat(rows, cols, MatType.CV_8UC1);
- imageRed = new Mat(rows, cols, MatType.CV_8UC1);
- for (int i = 0; i < rows; i++)
- {
- for (int j = 0; j < cols; j++)
- {
- int b = image.Get<Vec3b>(i, j)[0];
- int g = image.Get<Vec3b>(i, j)[1];
- int r = image.Get<Vec3b>(i, j)[2];
- imageBlue.Set<int>(i, j, b);
- imageGreen.Set<int>(i, j, g);
- imageRed.Set<int>(i, j, r);
- }
- }
- }
- /*
- * 摘要:
- * 对图片进行Sobel边缘检测,输出的是横向检测与纵向检测混合之后的结果
- */
- public static void Sobel(Mat imageContour,out Mat imageSobel)
- {
- //横向检测
- Mat grad_x = new Mat();
- Mat grad_x2 = new Mat();
- Cv2.Sobel(imageContour, grad_x, MatType.CV_16S, 1, 0);
- Cv2.ConvertScaleAbs(grad_x, grad_x2);
- //纵向检测
- Mat grad_y = new Mat();
- Mat grad_y2 = new Mat();
- Cv2.Sobel(imageContour, grad_y, MatType.CV_16S, 0, 1);
- Cv2.ConvertScaleAbs(grad_y, grad_y2);
- //横纵向混合平均
- imageSobel = new Mat();
- Cv2.AddWeighted(grad_x2, 0.5, grad_y2, 0.5, 0, imageSobel);
- }
- /*
- * 摘要:
- * 标注线条(竖向的标记线条)
- * 参数:
- * image:
- * 画线条的图片
- * x1,y1,x2,y2:
- * 线条端点的横纵坐标
- * data:
- * 显示数据
- */
- public static void LabelVertical(Mat image, int x1, int y1, int x2, int y2, double data)
- {
- double proportion = 0.2689;
- data = data * proportion;
- double middle = (y1 + y2) / 2;
- LineShow(image, x1, y1, x2, y2, "blue");
- LineShow(image, x1 - 5, y1, x1 + 5, y1, "blue");
- LineShow(image, x1 - 5, y2, x1 + 5, y2, "blue");
- TextShow(image, data, x1, (int)middle);
- }
- /*
- * 摘要:
- * 标注线条(横向的标记线条)
- * 参数:
- * image:
- * 画线条的图片
- * x1,y1,x2,y2:
- * 线条端点的横纵坐标
- * data:
- * 显示数据
- */
- public static void LableHorizontal(Mat image, int x1, int y1, int x2, int y2, double data)
- {
- double proportion = 0.2689;
- data = data * proportion;
- double middle = (x1 + x2) / 2;
- LineShow(image, x1, y1, x2, y2, "blue");
- LineShow(image, x1, y1 - 5, x1, y1 + 5, "blue");
- LineShow(image, x2, y1 - 5, x2, y1 + 5, "blue");
- TextShow(image, data, (int)middle, y1);
- }
- // 深盲孔子程序
- /*
- * 摘要:
- * 获得胶体区域的二值图
- * 参数:
- * imageContour:
- * 目标区域图,用作掩膜
- * imageRed:
- * 原图红色通道图
- * result:
- * 输出图片
- * upperBound:
- * 上界
- * lowerBound:
- * 下界
- */
- public static void GlueArea(Mat imageContour, Mat imageRed, out Mat result, int upperBound, int lowerBound,int leftBound,int rightBound)
- {
- int rows = lowerBound - upperBound;
- int cols = rightBound - leftBound;
- // 掩膜
- Mat image = new Mat(imageRed.Size(), imageRed.Type());
- image.CopyTo(imageRed, ~imageContour);
- // 得到胶体区域
- Mat glue = new Mat(rows, cols, imageRed.Type());
- BasFunction.InterceptMat(image, out glue, upperBound, lowerBound, leftBound, rightBound);
- // 滤波
- Mat glueFilter = new Mat(glue.Size(), glue.Type());
- Cv2.Blur(glue, glueFilter, new OpenCvSharp.Size(3, 3));
- // 计算平均阈值
- double threshold = 0;
- AverageThreshold(glueFilter, out threshold);
- // 阈值分割
- Mat thresh = new Mat();
- Cv2.Threshold(glueFilter, thresh, threshold, 255, ThresholdTypes.Binary);
- // 闭运算去噪(去除小孔)
- Mat close = new Mat();
- Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5));// 结构元素
- Cv2.MorphologyEx(thresh, close, MorphTypes.Close, se);
- // 腐蚀去噪(去除小点)
- Mat se2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(10, 1));// 结构元素
- Mat erode = new Mat();
- Cv2.Erode(close, erode, se);// 腐蚀
- // 边缘检测
- Mat sobel = new Mat();
- Sobel(erode, out sobel);
- // 输出
- result =new Mat(imageRed.Size(),imageRed.Type());
- for (int i = 0; i < rows; i++)
- {
- for (int j = 0; j < cols; j--)
- {
- int value = erode.Get<int>(i, j);
- result.Set<int>(i + upperBound, j + leftBound, value);
- }
- }
- }
- /*
- * 摘要:
- * 计算胶内缩数据的上胶边界
- * 参数:
- * imageContour:
- * 目标区域图
- * upperWaist:
- * 输出的上胶边界,先左后右
- * upperBound:
- * 提取区域的上界
- * lowerBound:
- * 提取区域的下界
- * middle:
- * 应是孔径的中心
- */
- public static void GetWaist(Mat imageContour, out int[] upperWaist, int upperBound, int lowerBound, int middle)
- {
- // 上胶区域
- Mat waist = new Mat();
- BasFunction.InterceptMat(~imageContour, out waist, upperBound, lowerBound, 0, imageContour.Cols);
- // 转数组
- int[,] arrayWaist = BasFunction.Mat2Array(waist);
- arrayWaist = BasFunction.ConversionRange(arrayWaist);
- // 每列求和
- int[] sum = BasFunction.Sum(arrayWaist, 1);
- // 遍历,找到上胶边界
- int leftWaist = 0;
- int rightWaist = 0;
- for (int j = middle; j > 1; j--)
- {
- if (sum[j] > 0)
- {
- leftWaist = j + 1;
- break;
- }
- }
- for (int j = middle; j < imageContour.Cols; j++)
- {
- if (sum[j] > 0)
- {
- rightWaist = j - 1;
- break;
- }
- }
- // 打包输出
- upperWaist = new int[2] { leftWaist, rightWaist };
- }
- /*
- * 摘要:
- * 计算下胶边界(外部)
- * 参数:
- * imageContour:
- * 目标区域图
- * lowerWaist:
- * 输出的边界,先左后右
- * upperBound:
- * 区域上界
- * lowerBound:
- * 区域下界
- * dataArea:
- * 数据提取区域,其中dataArea[0]与dataArea[3]用作左右边界
- */
- public static void GetLowerWaist(Mat imageContour, out int[] lowerWaist, int upperBound, int lowerBound, int[] dataArea)
- {
- // 截取下胶区域
- Mat waist = new Mat();
- BasFunction.InterceptMat(imageContour, out waist, upperBound - 10, lowerBound - 20, dataArea[0], dataArea[3]);
- // 转数组
- int[,] arrayWaist = BasFunction.Mat2Array(waist);
- arrayWaist = BasFunction.ConversionRange(arrayWaist);
- // 每列求和
- int[] sum = BasFunction.Sum(arrayWaist, 1);
- // 遍历找到下胶边界
- int leftWaist = 0;
- int rightWaist = 0;
- for (int j = dataArea[0]; j < dataArea[3]; j++)
- {
- if (sum[j] > 0)
- {
- leftWaist = j - 1;
- break;
- }
- }
- for (int j = dataArea[3]; j > dataArea[0]; j--)
- {
- if (sum[j] > 0)
- {
- rightWaist = j + 1;
- break;
- }
- }
- lowerWaist = new int[2] { leftWaist, rightWaist };
- }
- // 槽孔子程序
- /*
- * 摘要:
- * 为了去除亮光,计算两部分区域的边界
- * 参数:
- * array:
- * 输入二值化后的目标区域图片数组
- * b2,b3:
- * 输出的两部分边界
- */
- public static void SplitArea(int[,] array, out int b2, out int b3)
- {
- int[] sum = BasFunction.Sum(array, 1);// 每列求和
- int b1 = 0;// 左边开始
- b2 = 0;// 左边结束
- b3 = 0;// 右边结束
- int b4 = 0;// 右边开始
- for (int j = 0; j < sum.Length; j++)
- {
- if (sum[j] > 0)
- {
- b1 = j;
- break;
- }
- }
- for (int j = b1; j < sum.Length; j++)
- {
- if (sum[j] == 0)
- {
- b2 = j;
- break;
- }
- }
- for (int j = sum.Length - 1; j > b2; j--)
- {
- if (sum[j] > 0)
- {
- b4 = j;
- break;
- }
- }
- for (int j = b4; j > b2; j--)
- {
- if (sum[j] == 0)
- {
- b3 = j;
- break;
- }
- }
- }
- /*
- * 摘要:
- * 将槽孔的中间部分填充
- * 参数:
- * imageContour:
- * 输入目标区域图片
- * result:
- * 输出填充好的结果
- */
- public static void Fill(Mat imageContour, out Mat result)
- {
- int[,] arrayContour = BasFunction.Mat2Array(imageContour);
- arrayContour = BasFunction.ConversionRange(arrayContour);
- int[] sum2 = BasFunction.Sum(arrayContour, 2);// 每行求和
- int max = BasFunction.Max(sum2);
- int y1 = 0;
- int y2 = 0;// 填充上下界
- for (int i = 0; i < imageContour.Rows; i++)
- {
- if (sum2[i] > max - 50)
- {
- y1 = i;
- break;
- }
- }
- for (int i = imageContour.Rows - 1; i > 0; i--)
- {
- if (sum2[i] > max - 50)
- {
- y2 = i;
- break;
- }
- }
- BasFunction.SetNumber(imageContour, out result, y1, y2, 0, imageContour.Cols, 255);
- }
- /*
- * 摘要:
- * 求槽孔的数据提取区域
- * 参数:
- * image:
- * 输入的填充后的图像
- * dataArea:
- * 输出的提取区域,先左后右
- */
- public static void DataArea2(Mat image, out int[] dataArea)
- {
- // 转成数组
- int[,] array = BasFunction.Mat2Array(image);
- array = BasFunction.ConversionRange(array);
- int[] sum = BasFunction.Sum(array, 1);// 每列求和
- int max = BasFunction.Max(sum);// 和最大值
- dataArea = new int[2];
- for (int j = 0; j < sum.Length; j++)
- {
- if (sum[j] > max - 10)
- {
- dataArea[0] = j;
- break;
- }
- }
- for (int j = sum.Length - 1; j > 0; j--)
- {
- if (sum[j] > max - 10)
- {
- dataArea[1] = j;
- break;
- }
- }
- }
- /*
- * 摘要:
- * 提取竖线(从右往左)
- * 参数:
- * array:
- * 输入轮廓线的数组
- * result:
- * 输出平均横坐标
- * upperBound,lowerBound:
- * 提取的上下边界
- */
- public static void ExtractVerticalLines(int[,] array, out double result, int upperBound, int lowerBound)
- {
- int rows = array.GetLength(0);
- int cols = array.GetLength(1);
- int[] coordinate = new int[rows];// 线条内有点的横坐标
- for (int i = upperBound; i < lowerBound; i++)
- {
- for (int j = cols - 1; j > 0; j--)
- {
- if (array[i, j] > 0)
- {
- coordinate[i] = j;
- break;
- }
- }
- }
- // 计算横坐标之和
- int sum = 0;
- BasFunction.Sum(coordinate, out sum);
- // 点的个数
- int count = 0;
- BasFunction.Count(coordinate, out count);
- // 输出平均横坐标
- result = sum / count;
- }
- /*
- * 摘要:
- * 提取非第一列竖线(从右往左)
- * 参数:
- * array:
- * 轮廓线数组
- * result:
- * 输出平均横坐标结果
- * upperBound,lowerBound:
- * 提取区域上下界
- * basic:
- * 前一条竖线横坐标,作为基准
- */
- public static void ExtractVerticalLines(int[,] array, out double result, int upperBound, int lowerBound,double basic)
- {
- int rows = array.GetLength(0);
- int cols = array.GetLength(1);
- int[] coordinate = new int[rows];// 线条内有点的横坐标
- // 寻找的左右范围
- int leftBound = (int)basic - 45;
- int rightBound = (int)basic - 15;
- //初始化,记录横坐标的数组全为0
- for (int i = 0; i < rows; i++)
- {
- coordinate[i] = 0;
- }
- //计算线条内非零点的个数
- int count = 0;
- BasFunction.Count(coordinate, out count);
- //当点的个数少于5的时候循环
- while (count < 5)
- {
- //每次循环,寻找范围向左移动5个像素
- leftBound = leftBound - 5;
- rightBound = rightBound - 5;
- //遍历,寻找线条上的点,并记录横坐标
- for (int i = upperBound; i<lowerBound; i++)
- {
- for (int j = rightBound; j >leftBound; j--)
- {
- if (array[i, j] > 0)
- {
- coordinate[i] = j;
- break;
- }
- }
- }
- //重新计算线条内点的个数
- BasFunction.Count(coordinate, out count);
- }
- //横坐标之和
- int sum = 0;
- BasFunction.Sum(coordinate, out sum);
- //平均横坐标
- result = sum / count;
- }
- /*
- * 摘要:
- * 提取竖线(从左往右)
- * 参数:
- * array:
- * 输入轮廓线的数组
- * result:
- * 输出平均横坐标
- * upperBound,lowerBound:
- * 提取的上下边界
- */
- public static void ExtractVerticalLines2(int[,] array, out double result, int upperBound, int lowerBound)
- {
- int rows = array.GetLength(0);
- int cols = array.GetLength(1);
- int[] coordinate = new int[rows];// 线条内有点的横坐标
- for (int i = upperBound; i < lowerBound; i++)
- {
- for (int j = 0; j < cols; j++)
- {
- if (array[i, j] > 0)
- {
- coordinate[i] = j;
- break;
- }
- }
- }
- // 计算横坐标之和
- int sum = 0;
- BasFunction.Sum(coordinate, out sum);
- // 点的个数
- int count = 0;
- BasFunction.Count(coordinate, out count);
- // 输出平均横坐标
- result = sum / count;
- }
- /*
- * 摘要:
- * 提取非第一列竖线(从左往右)
- * 参数:
- * array:
- * 轮廓线数组
- * result:
- * 输出平均横坐标结果
- * upperBound,lowerBound:
- * 提取区域上下界
- * basic:
- * 前一条竖线横坐标,作为基准
- */
- public static void ExtractVerticalLines2(int[,] array, out double result, int upperBound, int lowerBound, double basic)
- {
- int rows = array.GetLength(0);
- int cols = array.GetLength(1);
- int[] coordinate = new int[rows];// 线条内有点的横坐标
- // 寻找的左右范围
- int leftBound = (int)basic + 15;
- int rightBound = (int)basic + 45;
- //初始化,记录横坐标的数组全为0
- for (int i = 0; i < rows; i++)
- {
- coordinate[i] = 0;
- }
- //计算线条内非零点的个数
- int count = 0;
- BasFunction.Count(coordinate, out count);
- //当点的个数少于5的时候循环
- while (count < 5)
- {
- //每次循环,寻找范围向左移动5个像素
- leftBound = leftBound + 5;
- rightBound = rightBound + 5;
- //遍历,寻找线条上的点,并记录横坐标
- for (int i = upperBound; i < lowerBound; i++)
- {
- for (int j = leftBound; j < rightBound; j++)
- {
- if (array[i, j] > 0)
- {
- coordinate[i] = j;
- break;
- }
- }
- }
- //重新计算线条内点的个数
- BasFunction.Count(coordinate, out count);
- }
- //横坐标之和
- int sum = 0;
- BasFunction.Sum(coordinate, out sum);
- //平均横坐标
- result = sum / count;
- }
- /*
- * 摘要:
- * 计算粗糙度
- * 参数:
- * array:
- * 轮廓线条数组
- * upperBound,lowerBound:
- * 粗糙度上下界
- * basic:
- * 基准线条
- * cucaodu:
- * 输出粗糙度
- */
- public static void Cucaodu(int[,] array, int upperBound, int lowerBound, int basic, out int cucaodu, out int[] coordinate)
- {
- // 截取粗糙度附近线条
- int[,] seg = BasFunction.InterceptArray(array, upperBound, lowerBound, 0, array.GetLength(1));
- // 得到线上点的坐标
- int[,] zuobiao ;
- BasFunction.Find(seg, out zuobiao);
- // 遍历,计算粗糙度最大的时候的值和坐标位置
- cucaodu = 0;
- int t = 0;
- coordinate = new int[2];
- for (int i = 0; i < zuobiao.GetLength(0); i++)
- {
- t = Math.Abs(zuobiao[i, 1] - basic);
- if (cucaodu < t && t < 50)
- {
- cucaodu = t;
- coordinate[0] = zuobiao[i,0] + upperBound;
- coordinate[1] = zuobiao[i,1];
- }
- }
- }
- /*
- * 摘要:
- * 将槽孔四层的亮光去掉
- * 参数:
- * imageContour:
- * 目标区域二值化图
- * imageRed:
- * 红色通道图
- * result:
- * 输出去除亮光的目标区域图
- * direction:
- * 选择是左边还是右边,“left”,“right”
- */
- public static void RemoveLightSiceng(Mat imageContour, Mat imageRed, out Mat result, string direction)
- {
- // 对红色通道进行边缘检测
- Mat imageRedSobel = new Mat();
- SubFunction.Sobel(imageRed, out imageRedSobel);
- // 竖向腐蚀三次
- Mat se2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(1, 3));
- Mat imageErode = new Mat();
- Cv2.Erode(imageRedSobel, imageErode, se2);
- Cv2.Erode(imageErode, imageErode, se2);
- Cv2.Erode(imageErode, imageErode, se2);
- // 转成数组
- int[,] arrayErode = BasFunction.Mat2Array(imageErode);
- arrayErode = BasFunction.ConversionRange(arrayErode);
- // 每列求和
- int[] sum = BasFunction.Sum(arrayErode, 1);
- // 最大值
- int max = BasFunction.Max(sum);
- // 遍历寻找边界
- int border = 0;
- result = imageContour;
- switch (direction)
- {
- case "left":
- for (int j = imageRed.Cols - 1; j > 0; j--)
- {
- if (sum[j] > max - 50)
- {
- border = j;
- break;
- }
- }
- for (int i = 0; i < imageRed.Rows; i++)
- {
- for (int j = border; j < imageRed.Cols; j++)
- {
- result.Set<byte>(i, j, 0);
- }
- }
- break;
- case "right":
- for (int j = 0; j < imageRed.Cols; j++)
- {
- if (sum[j] > max - 50)
- {
- border = j;
- break;
- }
- }
- for (int i = 0; i < imageRed.Rows; i++)
- {
- for (int j = 0; j < border; j++)
- {
- result.Set<byte>(i, j, 0);
- }
- }
- break;
- default:
- break;
- }
- }
- // 蚀刻因子
- /*
- * 摘要:
- * 提取蚀刻因子的检测区域
- * 参数:
- * imageContour:
- * 输入目标区域二值化图像
- * dataArea:
- * 输出提取区域数组,分别是上、下、左、右边界
- */
- public static void SKYZDataArea(Mat imageContour, out int[] dataArea)
- {
- // 转数组
- int[,] arrayContour = BasFunction.Mat2Array(imageContour);
- arrayContour = BasFunction.ConversionRange(arrayContour);
- // 上下边界
- int[] sum = BasFunction.Sum(arrayContour, 2);
- dataArea = new int[4];
- for (int i = 0; i < imageContour.Rows; i++)
- {
- if (sum[i] > 0)
- {
- dataArea[0] = i;// 当某行不全为0时为上界
- break;
- }
- }
- for (int i = dataArea[0]; i < imageContour.Rows; i++)
- {
- if (sum[i] == 0)
- {
- dataArea[1] = i;// 当某行全为0时为下界
- break;
- }
- }
- // 左右边界
- int[,] arrayContour2 = BasFunction.InterceptArray(arrayContour, dataArea[0], dataArea[1], 0, imageContour.Cols);
- int[] sum2 = BasFunction.Sum(arrayContour2, 1);
- int middle = imageContour.Cols / 2;
- // 如果中间列大于0,则向左右找到全为0的列,如果中间列为0,则向右找到非零列和全零列
- if (sum2[middle] == 0)
- {
- for (int j = middle; j < imageContour.Cols; j++)
- {
- if (sum2[j] > 0)
- {
- dataArea[2] = j;
- break;
- }
- }
- for (int j = dataArea[2]; j < imageContour.Cols; j++)
- {
- if (sum2[j] == 0)
- {
- dataArea[3] = j;
- break;
- }
- }
- }
- else
- {
- for (int j = middle; j > 0; j--)
- {
- if (sum2[j] == 0)
- {
- dataArea[2] = j;
- break;
- }
- }
- for (int j = middle; j < imageContour.Cols; j++)
- {
- if (sum2[j] == 0)
- {
- dataArea[3] = j;
- break;
- }
- }
- }
- }
- /*
- * 摘要:
- * 提取最上面的线横纵坐标
- * 参数:
- * arrayData:
- * 输入截取后的数组
- * dataData:
- * 检测区域
- * upperX:
- * 横坐标(先左后右)
- */
- public static void UpperLine(int[,] arrayData, int[] dataArea,out int[] upperX)
- {
- // 计算上横线位置
- int[] size = new int[2] { dataArea[1] - dataArea[0], dataArea[3] - dataArea[2] }; // 先行数,后列数
- int[] sum = BasFunction.Sum(arrayData, 2);
- int upperY = 0;// 上横线纵坐标
- for (int i = 0; i < size[0]; i++)
- {
- if (sum[i] > size[1] * 4 / 5)
- {
- upperY = i;
- break;
- }
- }
- upperX = new int[2];// 上横线横坐标边界
- for (int j = 0; j < size[1]; j++)
- {
- if (arrayData[upperY, j] > 0)
- {
- upperX[0] = j;//左边界
- break;
- }
- }
- for (int j = upperX[0]; j < size[1]; j++)
- {
- if (arrayData[upperY, j] == 0)
- {
- upperX[1] = j;//右边界
- break;
- }
- }
- }
- /*
- * 摘要:
- * 计算上下顶点的坐标
- * 参数:
- * arrayData:
- * 输入截取后的数组
- * basic:
- * 寻找宽度的某一条线(基准)
- * upperY:
- * 上顶点的纵坐标
- * lowerY:
- * 下顶点的纵坐标
- */
- public static void LowerLine(int[,] arrayData, int basic, out int upperY,out int lowerY)
- {
- upperY = 0;
- lowerY = 0;
- int[] sum = BasFunction.Sum(arrayData,2);
- for (int i = 0; i < sum.Length; i++)
- {
- if (sum[i] > 0)
- {
- upperY = i;
- break;
- }
- }
- for (int i = upperY; i < sum.Length; i++)
- {
- if (arrayData[i, basic] > 0)
- {
- upperY = i;
- break;
- }
- }
- for (int i = sum.Length - 1; i > 0; i--)
- {
- if (sum[i] > 0)
- {
- lowerY = i;
- break;
- }
- }
- for (int i = lowerY - 1; i > 0; i--)
- {
- if (arrayData[i, basic] > 0)
- {
- lowerY = i;
- break;
- }
- }
- }
- }
- }
|