#define online
using DocumentFormat.OpenXml.Spreadsheet;
using HalconDotNet;
using OpenCvSharp;
using OpenCvSharp.XImgProc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace GeBoShi.SysCtrl
{
public static class OpencvUtils
{
public static int image_width = 2048;
public static int image_height = 2048;
#region 图像预处理
public static Mat Resize(Mat mat, int width, int height, out int xw)
{
OpenCvSharp.Size dsize = new OpenCvSharp.Size(width, height);
//Mat mat2 = new Mat();
//ResizeUniform(mat, dsize, out mat2, out xw);
xw = (width - mat.Cols) / 2;
Mat mat2 = new Mat(height, width, MatType.CV_8UC3, new Scalar(114, 114, 114));
Rect roi = new Rect((width - mat.Cols) / 2, (height - mat.Rows) / 2, mat.Cols, mat.Rows);
mat.CopyTo(new Mat(mat2, roi));
return mat2;
}
///
/// 等比例缩放
///
///
///
///
///
public static int ResizeUniform(Mat src, Size dst_size, out Mat dst, out int xw)
{
xw = 0;
int w = src.Cols;
int h = src.Rows;
int dst_w = dst_size.Width;
int dst_h = dst_size.Height;
//std::cout << "src: (" << h << ", " << w << ")" << std::endl;
dst = new Mat(dst_h, dst_w, MatType.CV_8UC3, new Scalar(114, 114, 114));
float[] ratio = new float[2];
float ratio_src = w * 1.0f / h;
float ratio_dst = dst_w * 1.0f / dst_h;
int tmp_w = 0;
int tmp_h = 0;
if (ratio_src > ratio_dst)
{
tmp_w = dst_w;
tmp_h = (int)(dst_w * 1.0f / w) * h;
ratio[0] = (float)w / (float)tmp_w;
ratio[1] = (float)h / (float)tmp_h;
}
else if (ratio_src < ratio_dst)
{
tmp_h = dst_h;
tmp_w = (int)((dst_h * 1.0f / h) * w);
ratio[0] = (float)w / (float)tmp_w;
ratio[1] = (float)h / (float)tmp_h;
}
else
{
Cv2.Resize(src, dst, dst_size);
ratio[0] = (float)w / (float)tmp_w;
ratio[1] = (float)h / (float)tmp_h;
return 0;
}
//std::cout << "tmp: (" << tmp_h << ", " << tmp_w << ")" << std::endl;
Mat tmp = new Mat();
Cv2.Resize(src, tmp, new Size(tmp_w, tmp_h));
unsafe
{
if (tmp_w != dst_w)
{ //高对齐,宽没对齐
int index_w = (int)((dst_w - tmp_w) / 2.0);
xw = index_w;
//std::cout << "index_w: " << index_w << std::endl;
for (int i = 0; i < dst_h; i++)
{
Buffer.MemoryCopy(IntPtr.Add(tmp.Data, i * tmp_w * 3).ToPointer(), IntPtr.Add(dst.Data, i * dst_w * 3 + index_w * 3).ToPointer(), tmp_w * 3, tmp_w * 3);
}
}
else if (tmp_h != dst_h)
{ //宽对齐, 高没有对齐
int index_h = (int)((dst_h - tmp_h) / 2.0);
//std::cout << "index_h: " << index_h << std::endl;
Buffer.MemoryCopy(tmp.Data.ToPointer(), IntPtr.Add(dst.Data, index_h * dst_w * 3).ToPointer(), tmp_w * tmp_h * 3, tmp_w * tmp_h * 3);
}
else
{
}
}
return 0;
}
public static Mat ResizeMat(Mat mat, int width, int height)
{
OpenCvSharp.Size dsize = new OpenCvSharp.Size(width, height);
Mat mat2 = new Mat();
mat2 = mat.Resize(dsize);
//Cv2.Resize(mat, mat2, dsize);
return mat2;
}
///
/// 计算合理宽幅
///
/// 多个相机图像总宽(外部去除重合部分)
///
public static int GetWidthForResize(int sumWidth)
{
//保证计算8x2 16个小图
int count = (int)Math.Round(sumWidth * 1.0f / image_width, 0);
count = 8;
return count * image_width;
//int count = sumWidth / image_width;
////int remainder = sumWidth % image_width;
//if (count % 2 == 0)
// return count * image_width;
//else
// return count * image_width+ image_width;
}
///
/// 裁切指定区域
///
///
///
///
///
///
///
public static Mat CutImage(Mat mat, int x, int y, int width, int height)
{
Rect roi = new Rect(x, y, width, height);
return new Mat(mat, roi).Clone();
}
#endregion
#region 裁边
///
/// 裁边
///
///
///
///
///
///
public static Mat getMaxInsetRect2(Mat mat_rgb, bool isLeft, int marginHoleWidth, bool IsAI, out int marginWidth)
{
int bian = 3500;
Rect Roi;
if (!isLeft)
Roi = new Rect(mat_rgb.Width - bian, 0, bian, mat_rgb.Height);
else
Roi = new Rect(0, 0, bian, mat_rgb.Height);
int type = isLeft ? 1 : 0;
int len = 0;
if(!IsAI)
len = EdgeClipping2(mat_rgb, type, Roi, isLeft);
else
len = EdgeClipping3(mat_rgb, type, Roi, isLeft);
#if false
//Mat mat_rgb = new Mat("E:\\CPL\\测试代码\\边缘检测\\test\\test\\test\\img\\19.bmp");
Mat image_gray = new Mat();
Cv2.CvtColor(mat_rgb, image_gray, ColorConversionCodes.BGR2GRAY);
//cvtColor(image_RGB, image, COLOR_RGB2GRAY);
int height = image_gray.Rows;
int width = image_gray.Cols;
// 算法定义:取均分5段图片的五条横线,经过一系列处理之后,二值化,找到沿边位置,然后取均值作为直边,在缩进一段有针眼的位置
// 定义每段的行数
int num_rows = 5;
int segment_height = height / num_rows - 1;
// 定义空数组保存结果
int[] total = new int[num_rows];
// 平均截取5行数据并处理图像
for (int i = 0; i < num_rows; i++)
{
// 截取当前行的图像
int start_row = i * segment_height;
Rect roi = new Rect(0, start_row, width, 1);
Mat current_segment = image_gray.Clone(roi);
// 对当前行的图像进行平滑处理
Mat smoothed_image = new Mat();
Cv2.GaussianBlur(current_segment, smoothed_image, new Size(5, 1), 0);
// 计算当前行的灰度直方图
Mat absolute_histo = new Mat();
Cv2.CalcHist(new Mat[] { smoothed_image }, new int[] { 0 }, new Mat(), absolute_histo, 1, new int[] { 256 }, new Rangef[] { new Rangef(0, 256) });
Cv2.GaussianBlur(current_segment, smoothed_image, new Size(19, 1), 0);
// 对图片进行分割i+1
//double otsu_threshold;
//threshold(smoothed_image, smoothed_image, 0, 255, THRESH_BINARY + THRESH_OTSU, &otsu_threshold);
Cv2.Threshold(smoothed_image, smoothed_image, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
// 使用形态学操作进行孔洞填充
Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(25, 1));
Mat filled_image = new Mat();
Cv2.MorphologyEx(smoothed_image, filled_image, MorphTypes.Close, kernel);
// 取较长的一个值作为皮革的宽度
int num_255 = Cv2.CountNonZero(filled_image);
int length_t = (num_255 > width / 2) ? num_255 : width - num_255;
total[i] = (length_t);
API.OutputDebugString($"getMaxInsetRect2: 【{i + 1}】{length_t}={num_255}|{width}");
}
// 取平均值作为宽度
int length = (int)total.Average();
marginWidth = width-length;
#endif
int length = len; //(len > mat_rgb.Width / 2) ? len : mat_rgb.Width - len;
if (isLeft)
marginWidth = length;
else
marginWidth = mat_rgb.Width - length;
// 判断数据是否异常,判断当前线段的宽度是否大于设定像素的偏差
//int abnormal_pxl = 200;
//for (int i = 0; i < num_rows; i++)
//{
// if (Math.Abs(total[i] - length) > abnormal_pxl)
// throw new Exception("数据异常,当段图片的宽度有问题!");
//}
//右侧相机,拍摄产品,边缘位于右侧判断,缩进100像素,去点针眼
//Cv2.Line(mat_rgb, new Point(length - 100, 0), new Point(length - 100, height), new Scalar(255, 0, 0), 20);
////左侧相机,拍摄产品,边缘位于左侧判断,缩进100像素,去点针眼
//Cv2.Line(mat_rgb, new Point(width - length + 100, 0), new Point(width - length + 100, height), new Scalar(0, 255, 0), 20);
//int decWidth = width - length + marginHoleWidth;
//if (isLeft)
// return cutImage(mat_rgb, decWidth, 0, width- decWidth, height);
//else
// return cutImage(mat_rgb, 0, 0, width - decWidth, height);
//API.OutputDebugString($"getMaxInsetRect2:margin={marginWidth},length={length}({marginHoleWidth}),isLeft={isLeft},mat_rgb={mat_rgb.Width}*{mat_rgb.Height},w={length - marginHoleWidth},h={mat_rgb.Height}");
#if online
if (isLeft)
return CutImage(mat_rgb, length + marginHoleWidth, 0, mat_rgb.Width - length - marginHoleWidth, mat_rgb.Height);
else
return CutImage(mat_rgb, 0, 0, length - marginHoleWidth, mat_rgb.Height);
#else
if (isLeft)
{
Cv2.Line(mat_rgb, new Point(length + marginHoleWidth, 0), new Point(length + marginHoleWidth, mat_rgb.Height), new Scalar(255, 0, 0), 20);
return mat_rgb;
}
else
{
Cv2.Line(mat_rgb, new Point(length - marginHoleWidth, 0), new Point(length - marginHoleWidth, mat_rgb.Height), new Scalar(0, 255, 0), 20);
return mat_rgb;
}
#endif
}
///
/// 寻边算法
///
///
///
///
///
///
private static int EdgeClipping2(Mat image, int FindType, Rect Roi, bool IsLeft)
{
Mat mat_rgb = image.Clone(Roi);
int height = mat_rgb.Rows;
int width = mat_rgb.Cols;
int sf = 10; //缩放比例
int pix = 5; //获取均值区域长宽像素
int pointNum = 15; //获取找遍点数
int offsetGray = 5; //二值化偏差
//按比例缩放
int sf_height = height / sf;
int sf_width = width / sf;
Cv2.Resize(mat_rgb, mat_rgb, new Size(sf_width, sf_height), 0, 0, InterpolationFlags.Linear);
//mat_rgb = mat_rgb.Resize(new Size(sf_width, sf_height));
int[] maxlev = new int[3] { 3, 1, 0 };
int[] srlev = new int[3] { 29, 25, 11 };
int length_t = 0;
Mat[] lineImg = new Mat[3];
List lines = new List();
List total_t = new List();
for (int lv = 0; lv < 3; lv++)
{
lines.Clear();
total_t.Clear();
Mat himg = mat_rgb.Clone();
//mat_rgb = mat_rgb.PyrMeanShiftFiltering(10, 27, 3);
Cv2.PyrMeanShiftFiltering(himg, himg, 10, srlev[lv], maxlev[lv]);//10,17;
//分通道处理
Mat[] mv = Cv2.Split(himg);
for (int cht = 0; cht < 3; cht++)
{
//转灰度图
//mat_rgb = mat_rgb.CvtColor(ColorConversionCodes.BGR2GRAY);
Mat image_gray = new Mat();
image_gray = mv[cht];
//image_gray.ImWrite($"image_gray{cht}.jpg");
Mat image_Canny = new Mat();
Cv2.Canny(image_gray, image_Canny, 32, 64, 3);
//image_Canny.ImWrite($"image_Canny{cht}.jpg");
var lins = Cv2.HoughLinesP(image_Canny, 1, Math.PI / 360, 0, 20, 10);
lineImg[cht] = new Mat(new Size(himg.Cols, himg.Rows), MatType.CV_8UC1, new Scalar());
lines.Add(lins.Length);
foreach (var item in lins)
{
var fdang = Math.Atan2((item.P2.Y - item.P1.Y), (item.P2.X - item.P1.X));
var ang = Math.Abs(fdang * (180 / Math.PI));
if (ang > 60 && ang < 120)
Cv2.Line(lineImg[cht], item.P1.X, item.P1.Y, item.P2.X, item.P2.Y, new Scalar(255, 255, 255), 2);
}
//lineImg[cht].ImWrite($"image_Canny2_{cht}.jpg");
//mat_rgb = mat_rgb.Canny(32, 64);
if (lins.Length >= 1)
break;
}
if (lines.Count > 0 && lines.Max() >= 1)
break;
}
//二值化
Mat image_Otsu = new Mat();
int hDis = sf_height / (pointNum + 2); //去除边缘两点
#if false //二值算法
List LeftAvg = new List();
List RightAvg = new List();
//double thb = Cv2.Threshold(image_gray, image_Otsu, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
#region 多点获取二值化均值
for (int i = 0; i < pointNum; i++)
{
Rect roiLeft = new Rect(0, hDis + hDis * i, pix, pix);
Mat current_segmentL = image_gray.Clone(roiLeft);
//Scalar ttr = current_segmentL.Mean();
LeftAvg.Add(current_segmentL.Mean().Val0);
Rect roiRight = new Rect(sf_width - pix, hDis + hDis * i, pix, pix);
Mat current_segmentR = image_gray.Clone(roiRight);
RightAvg.Add(current_segmentR.Mean().Val0);
}
double thres = 0;
if (IsLeft)
{
if (LeftAvg.Average() > RightAvg.Average())
thres = RightAvg.Max() + offsetGray;
else
thres = RightAvg.Min() - offsetGray;
}
else
{
if (LeftAvg.Average() > RightAvg.Average())
thres = LeftAvg.Min() - offsetGray;
else
thres = LeftAvg.Max() + offsetGray;
}
//double thres = (RightAvg.Average() + )/2;
#endregion
#endif
#if false
double min, max;
image_gray.MinMaxLoc(out min, out max);
double thres = (min + max) / 2;
#endif
#if false //二值化图片
//Cv2.Threshold(image_gray, image_Otsu, 0, 255, ThresholdTypes.Otsu);
double thb = Cv2.Threshold(image_gray, image_Otsu, thres, 255, ThresholdTypes.Binary);
image_Otsu.ImWrite("Otsu1.jpg");
Cv2.MedianBlur(image_Otsu, image_Otsu, 21);
image_Otsu.ImWrite("Otsu2.jpg");
endTime = DateTimeOffset.Now;
Console.WriteLine("灰度图二值化(ms): " + (endTime - startTime).TotalMilliseconds.ToString("0.000"));
startTime = DateTimeOffset.Now;
#else
/*
image_Otsu = image_Canny;
*/
#endif
int findex = lines.FindIndex(x => x == lines.Max());
image_Otsu = lineImg[findex];
// 定义空数组保存结果
int[] total = new int[pointNum];
total_t = new List();
//bool isLeft = FindType == 0 ? true : false;
// 平均截取pointNum行数据并处理图像
for (int i = 0; i < pointNum; i++)
{
// 截取当前行的图像
Rect roi = new Rect(0, hDis + hDis * i, sf_width, 1);
//Mat current_segment = image_Otsu.Clone(roi);
Mat current_segment = image_Otsu.Clone(roi);
#if false
#region 预处理
// 对当前行的图像进行平滑处理
Mat smoothed_image2 = new Mat();
Cv2.GaussianBlur(current_segment, smoothed_image2, new Size(5, 1), 0);
// 计算当前行的灰度直方图
Mat absolute_histo2 = new Mat();
Cv2.CalcHist(new Mat[] { smoothed_image2 }, new int[] { 0 }, new Mat(), absolute_histo2, 1, new int[] { 256 }, new Rangef[] { new Rangef(0, 256) });
Cv2.GaussianBlur(current_segment, smoothed_image2, new Size(9, 1), 0);
// 对图片进行分割
//double otsu_threshold;
//threshold(smoothed_image, smoothed_image, 0, 255, THRESH_BINARY + THRESH_OTSU, &otsu_threshold);
double otsu_threshold2 = Cv2.Threshold(smoothed_image2, smoothed_image2, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
// 使用形态学操作进行孔洞填充
Mat kernel3 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 1));
Mat filled_image3 = new Mat();
Cv2.MorphologyEx(smoothed_image2, filled_image3, MorphTypes.Close, kernel3);
#endregion
#else
//Mat filled_image3 = current_segment.Clone();
Mat filled_image3 = current_segment;
#endif
#if true
//从左到右判断边和从右到左判断边
int numX = 0;
byte tempVal = 0;
if (!IsLeft)
{
tempVal = filled_image3.At(0, 0);
//filled_image3.
for (int j = 0; j < filled_image3.Cols; j++)
{
if (filled_image3.At(0, j) != tempVal)
{
numX = j;
break;
}
}
}
else
{
tempVal = filled_image3.At(0, filled_image3.Cols - 1);
for (int j = filled_image3.Cols - 1; j >= 0; j--)
{
if (filled_image3.At(0, j) != tempVal)
{
numX = j;
break;
}
}
}
//int numX = 0;
//byte tempVal = 0;
//unsafe
//{
// byte* ptr = (byte*)filled_image3.Data;
// if (isLeft)
// {
// tempVal = ptr[0];
// for (int j = 0; j < filled_image3.Cols; j++)
// {
// if (ptr[j] != tempVal)
// {
// numX = j;
// break;
// }
// }
// }
// else
// {
// tempVal = ptr[filled_image3.Cols - 1];
// //tempVal = filled_image3.At(0, filled_image3.Cols - 1);
// for (int j = filled_image3.Cols - 1; j >= 0; j--)
// {
// if (ptr[j] != tempVal)
// {
// numX = j;
// break;
// }
// }
// }
//}
#else
int numX = Cv2.CountNonZero(filled_image3);
#endif
//int length_t = (numX > (sf_width / 2)) ? numX :sf_width - numX;
length_t = numX;
total[i] = (length_t);
if (length_t > 0)
total_t.Add(length_t);
current_segment.Dispose();
}
// 取平均值作为宽度
int length = 0;
if(total_t.Count> 0)
length = (int)total_t.Average();
//endTime = DateTimeOffset.Now;
//Console.WriteLine("计算边(ms): " + (endTime - startTime).TotalMilliseconds.ToString("0.000"));
// 判断数据是否异常,判断当前线段的宽度是否大于设定像素的偏差
//int abnormal_pxl = 100 / 4;
//for (int i = 0; i < pointNum; i++)
//{
// if (Math.Abs(total[i] - length) > abnormal_pxl)
// Console.WriteLine("数据异常!");
// //出现数据异常,当段图片的宽度有问题
//}
//乘上换算系数还原
length = length * sf + Roi.X;
//if ((length > 6520 && length < 6530) || (length > 1570 && length < 1590))
// ;
//else
// ;
mat_rgb.Dispose();
//himg.Dispose();
//image_gray.Dispose();
//image_Canny.Dispose();
//image_Otsu.Dispose();
return length;
}
private static StructuredEdgeDetection _edgeDetect;
public static void LoadEdgeMode()
{
if(_edgeDetect == null)
_edgeDetect = OpenCvSharp.XImgProc.CvXImgProc.CreateStructuredEdgeDetection("model.yml");
}
///
/// 模型寻边
///
///
///
///
///
///
private static int EdgeClipping3(Mat image, int FindType, Rect Roi, bool IsLeft)
{
Mat mat_rgb = image.Clone(Roi);
int height = mat_rgb.Rows;
int width = mat_rgb.Cols;
int sf = 10; //缩放比例
int pix = 5; //获取均值区域长宽像素
int pointNum = 15; //获取找遍点数
int offsetGray = 5; //二值化偏差
int length_t = 0;
List lines = new List();
List total_t = new List();
//按比例缩放
double sf_height = height / sf;
double sf_width = width / sf;
Cv2.Resize(mat_rgb, mat_rgb, new Size(sf_width, sf_height), 0, 0, InterpolationFlags.Linear);
Mat himg = new Mat();
Mat edgeimg = new Mat();
Cv2.CvtColor(mat_rgb, edgeimg, ColorConversionCodes.BGR2RGB);
Mat edges = new Mat();
edgeimg.ConvertTo(edgeimg, MatType.CV_32F, 1 / 255.0);
if(_edgeDetect == null)
LoadEdgeMode();
//Cv2.Normalize(edgeimg, edgeimg, 1.0, 0, NormTypes.L2, -1);
_edgeDetect.DetectEdges(edgeimg, edges);
Mat image_Otsu = new Mat();
int hDis = (int)sf_height / (pointNum + 2); //去除边缘两点
edges.ConvertTo(image_Otsu, MatType.CV_8U, 255.0);
Cv2.Threshold(image_Otsu, image_Otsu, 0, 255, ThresholdTypes.Otsu);
// 定义空数组保存结果
int[] total = new int[pointNum];
// 平均截取pointNum行数据并处理图像
for (int i = 0; i < pointNum; i++)
{
// 截取当前行的图像
Rect roi = new Rect(0, hDis + hDis * i, (int)sf_width, 1);
Mat current_segment = image_Otsu.Clone(roi);
//Mat filled_image3 = current_segment.Clone();
Mat filled_image3 = current_segment;
#if true
//从左到右判断边和从右到左判断边
int numX = 0;
int tm = 0;
byte tempVal = 0;
bool findOne = false;
if (IsLeft)
{
tempVal = filled_image3.At(0, 0);
//filled_image3.
for (int j = 0; j < filled_image3.Cols; j++)
{
if (filled_image3.At(0, j) != tempVal)
{
if (!findOne)
{
tm = j;
findOne = true;
tempVal = filled_image3.At(0, j);
}
else
{
//numX = j;
numX = (tm + j) / 2;
break;
}
}
}
}
else
{
tempVal = filled_image3.At(0, filled_image3.Cols - 1);
for (int j = filled_image3.Cols - 1; j >= 0; j--)
{
if (filled_image3.At(0, j) != tempVal)
{
if (!findOne)
{
tm = j;
findOne = true;
tempVal = filled_image3.At(0, j);
}
else
{
//numX = j;
numX = (tm + j) / 2;
break;
}
}
}
}
#else
int numX = Cv2.CountNonZero(filled_image3);
#endif
//length_t = (numX > (sf_width / 2)) ? numX :(int)(sf_width - numX);
length_t = numX;
total[i] = (length_t);
if (length_t > 0)
total_t.Add(length_t);
}
// 取平均值作为宽度
int length = 0;
if (total_t.Count > 0)
{
length = (int)total_t.Average();
if (IsLeft)
length = length - ConfMgr.Instance.SysConfigParams.Crop_offset;
else
length = length + ConfMgr.Instance.SysConfigParams.Crop_offset;
}
//乘上换算系数还原
length = length * sf + Roi.X;
return length;
}
#endregion
#region 合并
///
/// 合并MAT(宽高必需一致)
///
///
///
///
public static Mat MergeImage_sameSize(Mat[] mats, bool isHorizontal = true)
{
Mat matOut = new Mat();
if (isHorizontal)
Cv2.HConcat(mats, matOut);//横向拼接
else
Cv2.VConcat(mats, matOut);//纵向拼接
return matOut;
}
#endregion
#region MatToHalcon
public static void MatToHObject(Mat imgMat, out HObject imgHOject)
{
int ImageWidth = imgMat.Width;
int ImageHeight = imgMat.Height;
int channel = imgMat.Channels();
long size = ImageWidth * ImageHeight * channel;
int col_byte_num = ImageWidth * channel;
byte[] rgbValues = new byte[size];
unsafe
{
for (int i = 0; i < ImageHeight; i++)
{
IntPtr c = imgMat.Ptr(i);
// 一行一行将mat 像素复制到byte[]
Marshal.Copy(c, rgbValues, i * col_byte_num, col_byte_num);
}
void* p;
IntPtr ptr;
fixed (byte* pc = rgbValues)
{
p = (void*)pc;
ptr = new IntPtr(p);
}
if (channel == 1)
{
HOperatorSet.GenImage1(out imgHOject, "byte", ImageWidth, ImageHeight, ptr);
}
else
{
HOperatorSet.GenImageInterleaved(out imgHOject, ptr, "bgr", ImageWidth, ImageHeight, 0, "byte", 0, 0, 0, 0, -1, 0);
}
}
}
#if false
///
/// 把OpenCV图像转换到Halcon图像
///
/// OpenCV图像_Mat
/// Halcon图像_HObject
public HObject MatToHImage(Mat mImage)
{
try
{
HObject hImage;
int matChannels = 0; // 通道数
Type matType = null;
int width, height; // 宽,高
width = height = 0; // 宽,高初始化
// 获取通道数
matChannels = mImage.Channels();
if (matChannels == 0)
{
return null;
}
if (matChannels == 1) // 单通道
{
IntPtr ptr; // 灰度图通道
Mat[] mats = mImage.Split();
// 改自:Mat.GetImagePointer1(mImage, out ptr, out matType, out width, out height); // ptr=2157902018096 cType=byte width=830 height=822
ptr = mats[0].Data; // 取灰度图值
matType = mImage.GetType(); // byte
height = mImage.Rows; // 高
width = mImage.Cols; // 宽
// 改自:hImage = new HObject(new OpenCvSharp.Size(width, height), MatType.CV_8UC1, new Scalar(0));
byte[] dataGrayScaleImage = new byte[width * height]; //Mat dataGrayScaleImage = new Mat(new OpenCvSharp.Size(width, height), MatType.CV_8UC1);
unsafe
{
fixed (byte* ptrdata = dataGrayScaleImage)
{
#region 按行复制
//for (int i = 0; i < height; i++)
//{
// CopyMemory((IntPtr)(ptrdata + width * i), new IntPtr((long)ptr + width * i), width);
//}
#endregion
CopyMemory((IntPtr)ptrdata, new IntPtr((long)ptr), width * height);
HOperatorSet.GenImage1(out hImage, "byte", width, height, (IntPtr) ptrdata);
}
}
return hImage;
}
else if (matChannels == 3) // 三通道
{
IntPtr ptrRed; // R通道图
IntPtr ptrGreen; // G通道图
IntPtr ptrBlue; // B通道图
Mat[] mats = mImage.Split();
ptrRed = mats[0].Data; // 取R通道值
ptrGreen = mats[1].Data; // 取G通道值
ptrBlue = mats[2].Data; // 取B通道值
matType = mImage.GetType(); // 类型
height = mImage.Rows; // 高
width = mImage.Cols; // 宽
// 改自:hImage = new HObject(new OpenCvSharp.Size(width, height), MatType.CV_8UC1, new Scalar(0));
byte[] dataRed = new byte[width * height]; //Mat dataGrayScaleImage = new Mat(new OpenCvSharp.Size(width, height), MatType.CV_8UC1);
byte[] dataGreen = new byte[width * height];
byte[] dataBlue = new byte[width * height];
unsafe
{
fixed (byte* ptrdataRed = dataRed, ptrdataGreen = dataGreen, ptrdataBlue = dataBlue)
{
#region 按行复制
//HImage himg = new HImage("byte", width, height, (IntPtr)ptrdataRed);
//for (int i = 0; i < height; i++)
//{
// CopyMemory((IntPtr)(ptrdataRed + width * i), new IntPtr((long)ptrRed + width * i), width);
// CopyMemory((IntPtr)(ptrdataGreen + width * i), new IntPtr((long)ptrGreen + width * i), width);
// CopyMemory((IntPtr)(ptrdataBlue + width * i), new IntPtr((long)ptrBlue + width * i), width);
//}
#endregion
CopyMemory((IntPtr)ptrdataRed, new IntPtr((long)ptrRed), width * height); // 复制R通道
CopyMemory((IntPtr)ptrdataGreen, new IntPtr((long)ptrGreen), width * height); // 复制G通道
CopyMemory((IntPtr)ptrdataBlue, new IntPtr((long)ptrBlue), width * height); // 复制B通道
HOperatorSet.GenImage3(out hImage, "byte", width, height, (IntPtr)ptrdataRed, (IntPtr)ptrdataGreen, (IntPtr)ptrdataBlue); // 合成
}
}
return hImage;
}
else
{
return null;
}
}
catch (Exception ex)
{
throw ex;
}
}
#endif
#endregion
}
}