public static void Write(this CvMat matrix, XmlElement parent, string elemName) { XmlElement me = parent.OwnerDocument.CreateElement(elemName); me.SetAttribute("cols", matrix.Cols.ToString()); me.SetAttribute("rows", matrix.Rows.ToString()); me.SetAttribute("type", matrix.ElemType.ToString()); StringBuilder sb = new StringBuilder(); switch (matrix.ElemType) { case MatrixType.F32C1: for (int x = 0; x < matrix.Cols; ++x) { for (int y = 0; y < matrix.Rows; ++y) { if (sb.Length > 0) { sb.Append(", "); } sb.Append(matrix.Get2D(x, y).Val0); } } break; case MatrixType.F64C1: for (int x = 0; x < matrix.Cols; ++x) { for (int y = 0; y < matrix.Rows; ++y) { if (sb.Length > 0) { sb.Append(", "); } sb.Append(matrix.Get2D(x, y).Val0); } } break; default: throw new Exception("Write unsupported MatrixType " + matrix.ElemType); } me.SetAttribute("values", sb.ToString()); }
// => mat = 8bit binary image (0/255) // <= return true if of the 9 pixels in the point's area, at least 5 are white? public bool checkFeatureArea(CvMat mat, CvPoint2D32f point, int areaSize = 2) { float countWhites = 0; int x0 = (int)point.X - areaSize; if (x0 < 0) { return(false); } int y0 = (int)point.Y - areaSize; if (y0 < 0) { return(false); } int x1 = x0 + areaSize * 2; if (x1 >= mat.Cols) { return(false); } int y1 = y0 + areaSize * 2; if (y1 >= mat.Rows) { return(false); } for (int j = y0; j <= y1; ++j) { for (int i = x0; i <= x1; ++i) { //Console.WriteLine( "Checking " + i + "," + j + "=" + mat.Get2D( i, j ) ); if (mat.Get2D(j, i) != 0) { ++countWhites; } } } // we don't want white dots in black areas, or black dots in white areas float area = (x1 - x0 + 1) * (y1 - y0 + 1); if (countWhites >= area * 0.4f && countWhites <= area * 0.7f) { return(true); } return(false); }
// NOTE : Also seems not well written and craves optimization at places. P.A.N.A.R.G.O. // => frame = 8 bit greyscale CvMat static public void ContrastEnhancement(CvMat frame) { //CvMat originalFrame = frame; // return this if cannot enhance //if (frame.ElemType != MatrixType.U8C1) // frame = MatOps.Convert(frame, MatrixType.U8C1, 1 / 255.0 ); /////original histogram const int HistBinSize = 256; int[] histSizes = new int[1]; histSizes[0] = HistBinSize; CvHistogram hist = new CvHistogram(histSizes, HistogramFormat.Array); Cv.CalcArrHist(frame, hist, false); // size = 256 implied CvHistogram newHist = MatOps.CopyHistogram(hist); CvArr newHistBin = newHist.Bins; //double[] origVals = new double[hist.Bins.GetDims( 0 )]; List <double> origVals = new List <double>(HistBinSize); for (int i = 0; i < HistBinSize; i++) { double elem = newHistBin.GetReal1D(i); if (elem != 0) { origVals.Add(elem); } } // FIX : See no need for histL, since we have origVals //////histogram with only nonzero bins //CvMat histL = new CvMat( imageRows, imageCols, MatrixType.F32C1, new CvScalar( 0 ) ); //for (i = 0; i < origVals.size(); i++) // histL.at<float>( i, 0 ) = origVals.at( i ); List <double> peakValues = new List <double>(HistBinSize); //std::vector<int> peakValues; //////////3 bin search window for (int i = 1; i < origVals.Count - 2; ++i) { double elem = origVals[i]; if (elem > origVals[i - 1] && elem > origVals[i + 1]) { peakValues.Add(elem); } } if (peakValues.Count == 0) { //Console.Out.WriteLine( "Cannot enhance" ); return; // cannot enhance? } //////Upper threshold double threshUP = 0; for (int i = 0; i < peakValues.Count; ++i) { threshUP += peakValues[i]; } threshUP /= peakValues.Count; //////Lower threshold double threshDOWN = Math.Min((frame.Cols * frame.Rows), threshUP * origVals.Count) / 256.0; //Console.Out.WriteLine( "Enhance thresholds " + threshUP + "/" + threshDOWN ); //////histogram reconstruction CvArr histBins = hist.Bins; for (int i = 0; i < HistBinSize; ++i) { double histElem = histBins.GetReal1D(i); if (histElem > threshUP) { histBins.SetReal1D(i, threshUP); } else if (histElem <= threshUP && histElem >= threshDOWN) { continue; } else if (histElem < threshDOWN && histElem > 0) { histBins.SetReal1D(i, threshDOWN); } else if (histElem == 0) { continue; } } // accumulated values(?) double[] accVals = new double[HistBinSize]; //std::vector<int> accVals; accVals[0] = (histBins.GetReal1D(0)); for (int i = 1; i < HistBinSize; ++i) { accVals[i] = (accVals[i - 1] + histBins[i]); } byte[] lookUpTable = new byte[HistBinSize]; //cv::Mat lookUpTable = cv::Mat::zeros( hist.size(), CV_8UC1 ); for (int i = 0; i < HistBinSize; ++i) { lookUpTable[i] = (byte)(255.0 * accVals[i] / accVals[255]); } // assign computed values to input frame //Console.Out.Write( "Enhance-->" ); for (int i = 0; i < frame.Cols; ++i) { for (int j = 0; j < frame.Rows; ++j) { // there is NO mask, thus no need to check for; was: "if (mask.data)..." byte oldValue = (byte)frame.Get2D(j, i); byte newValue = lookUpTable[oldValue]; //if ((newValue <1 || newValue > 254) && (newValue != oldValue)) Console.Out.Write( oldValue + " " + newValue + "|"); frame.Set2D(j, i, newValue); //frame.SetReal2D( j, i, lookUpTable[ (int)(255.0 * frame.GetReal2D( j, i )) ] / 255.0); } } //Console.Out.WriteLine(); //frame = MatOps.Convert( frame, MatrixType.U8C1, 255.0 ); }
// 孤立輝点除去 // 周囲に輝点が無い場合,その輝点を消す static CvMat removeNoize(CvMat image) { // 1px大きい作業用画像 CvMat workImage = new CvMat( image.Rows+1, image.Cols+1, MatrixType.U8C1 ); image.CopyMakeBorder( workImage, new CvPoint(1, 1), BorderType.Constant ); // 走査 for ( int row = 0; row < image.Rows; row++ ) { for ( int col = 0; col < image.Cols; col++ ) { // 注目画素が暗点ならば何もしない if ( 0 == image.Get2D( row, col )) continue; // 範囲3x3の輝点が1ならば,中心画素を暗点にする CvRect rect = new CvRect( col, row, 3, 3 ); CvMat area; workImage.GetSubArr ( out area, rect ); int nonzero = area.CountNonZero(); if ( 1 == nonzero ) image.Set2D( row, col, 0 ); } } return image; }
/// <summary> /// CCD座標(cx,cy)->(az,alt)に変換 /// </summary> // // CCD座標(cx,cy):CCD中心からの誤差座標[pix] Std. Cam が基準(cx = x-xc, cy = y-yc) // 中心位置(az_c,alt_c)と視野回転(theta_c) // fl:焦点距離[mm], ccdpx,ccdpy:ピクセル間隔[mm] public void cxcy2azalt(double cx, double cy, double az_c, double alt_c, int mode, double theta_c, double fl, double ccdpx, double ccdpy, ref double az, ref double alt) { double rad = Math.PI / 180.0; double cxmm, cymm; //ターゲットの方向余弦 if (mode == mmEast) { cxmm = -cx * ccdpx; // +ccd -az cymm = +cy * ccdpy; // +ccd +alt } else { //mmWest cxmm = +cx * ccdpx; // +ccd +az cymm = -cy * ccdpy; // +ccd -alt } CvMat v1 = new CvMat(3, 1, MatrixType.F64C1); v1.Set2D(0, 0, fl); v1.Set2D(1, 0, -cxmm); v1.Set2D(2, 0, cymm); v1.Normalize(v1);// 方向余弦化 CvMat v2 = new CvMat(3, 1, MatrixType.F64C1); CvMat Rx = new CvMat(3, 3, MatrixType.F64C1); CvMat Rz = new CvMat(3, 3, MatrixType.F64C1); CvMat Ry = new CvMat(3, 3, MatrixType.F64C1); //Rx.rotX(-theta_c * rad); // 回転マトリクスをセット double sin = Math.Sin(-theta_c * rad); double cos = Math.Cos(-theta_c * rad); Rx.Set2D(0, 0, 1); Rx.Set2D(0, 1, 0); Rx.Set2D(0, 2, 0); Rx.Set2D(1, 0, 0); Rx.Set2D(1, 1, cos); Rx.Set2D(1, 2, -sin); Rx.Set2D(2, 0, 0); Rx.Set2D(2, 1, sin); Rx.Set2D(2, 2, cos); //Rz.rotZ(-az_c *rad ); // 天球座標系と回転方向が逆なのでマイナス sin = Math.Sin(-az_c * rad); cos = Math.Cos(-az_c * rad); Rz.Set2D(0, 0, cos); Rz.Set2D(0, 1, -sin); Rz.Set2D(0, 2, 0); Rz.Set2D(1, 0, sin); Rz.Set2D(1, 1, cos); Rz.Set2D(1, 2, 0); Rz.Set2D(2, 0, 0); Rz.Set2D(2, 1, 0); Rz.Set2D(2, 2, 1); //Ry.rotY(-alt_c *rad ); // 回転マトリクスをセット sin = Math.Sin(-alt_c * rad); cos = Math.Cos(-alt_c * rad); Ry.Set2D(0, 0, cos); Ry.Set2D(0, 1, 0); Ry.Set2D(0, 2, sin); Ry.Set2D(1, 0, 0); Ry.Set2D(1, 1, 1); Ry.Set2D(1, 2, 0); Ry.Set2D(2, 0, -sin); Ry.Set2D(2, 1, 0); Ry.Set2D(2, 2, cos); v2 = Rz * (Ry * (Rx * v1)); // 順番注意(画像中心をx軸に一致させている状態がスタート) // Retrun Val az = Math.Atan2(-v2.Get2D(1, 0), v2.Get2D(0, 0)) / rad; if (az < 0) { az += 360; } alt = Math.Asin(v2.Get2D(2, 0)) / rad; // //Az_Cとの距離が近い値を採用 // double az2 = az - 360; // double az3 = az + 360; // double dis1 = Math.Abs(az - az_c); // double dis2 = Math.Abs(az2 - az_c); // double dis3 = Math.Abs(az3 - az_c); // if (dis1 > dis2) az = az2; // if (dis1 > dis3) az = az3; }