/// <summary> /// 1枚のイメージからフィルム距離を返す。波長と、各面の真の面間隔と実測した2θが必要 /// </summary> /// <param name="p"></param> /// <param name="WaveLength"></param> /// <param name="FilmDistance"></param> /// <param name="FilmDistanceDev"></param> public static void FindFilmDistanceFromWaveLength(List <EllipseParameter> ellipses, double WaveLength, ref double FilmDistance, ref double FilmDistanceDev) { if (ellipses == null || ellipses.Count < 1) { return; } double tempTotal = 0; double weightTotal = 0; double temp, weight; List <double> FD = new List <double>(); for (int i = 0; i < ellipses.Count; i++) { for (int j = 0; j < ellipses[i].millimeters.Count; j++) { if (!double.IsNaN(ellipses[i].millimeters[j])) { temp = ellipses[i].millimeters[j] / Math.Tan(2 * Math.Asin(WaveLength / 2.0 / ellipses[i].d)); weight = 1;//Math.Pow(Math.Sin(Math.Atan(p[i].pixel1 * p[i].pixelSize / p[i].filmDistance1)), 2); tempTotal += temp * weight; weightTotal += weight; FD.Add(temp); } } } if (weightTotal > 0 && !double.IsInfinity(weightTotal)) { FilmDistance = tempTotal / weightTotal; FilmDistanceDev = Statistics.Deviation(FD.ToArray()) / Math.Sqrt(FD.Count); } }
/// <summary> /// 楕円の中心群とそれらの半径から、真の中心のオフセット位置(offset)と傾き(tau, phi)とそれらの誤差を返す /// </summary> /// <param name="EllipseCenter"></param> /// <param name="Radius"></param> /// <param name="CameraLength"></param> /// <param name="offset"></param> /// <param name="offsetDev"></param> /// <param name="tau"></param> /// <param name="tauDev"></param> /// <param name="phi"></param> /// <param name="phiDev"></param> public static void GetTiltAndOffset(PointD[] EllipseCenter, double[] Radius, double CameraLength, ref PointD offset, ref PointD offsetDev, ref double tau, ref double tauDev, ref double phi, ref double phiDev) { //任意の二点を選んでoffset, tau, phiを計算する List <double> offsetXList = new List <double>(); List <double> offsetYList = new List <double>(); List <double> tauList = new List <double>(); List <double> phiList = new List <double>(); for (int i = 0; i < EllipseCenter.Length; i++) { for (int j = i + 1; j < EllipseCenter.Length; j++) { PointD[] ellipseCenterTemp = new PointD[] { EllipseCenter[i], EllipseCenter[j] }; double[] radiusTemp = new double[] { Radius[i], Radius[j] }; PointD offsetTemp = offset; double tauTemp = tau; double phiTemp = phi; GetTiltAndOffset(ellipseCenterTemp, radiusTemp, CameraLength, ref offsetTemp, ref tauTemp, ref phiTemp); offsetXList.Add(offsetTemp.X); offsetYList.Add(offsetTemp.Y); tauList.Add(tauTemp); phiList.Add(phiTemp); } } offsetDev = new PointD(Statistics.Deviation(offsetXList.ToArray()), Statistics.Deviation(offsetYList.ToArray())); tauDev = Statistics.Deviation(tauList.ToArray()); double phiDev1, phiDev2; phiDev1 = Statistics.Deviation(phiList.ToArray()); for (int i = 0; i < phiList.Count; i++) { if (phiList[i] < 0) { phiList[i] += Math.PI; } } phiDev2 = Statistics.Deviation(phiList.ToArray()); phiDev = Math.Min(phiDev1, phiDev2); //全EllipseCenterを用いて、offset, tau, phiを計算する GetTiltAndOffset(EllipseCenter, Radius, CameraLength, ref offset, ref tau, ref phi); }
/// <summary> /// 楕円の方程式から、その楕円群をもっとも真円に近づけるパラメータ(PixX, PixY, Ksi)を求める /// </summary> /// <param name="ellipse"></param> /// <param name="PixX"></param> /// <param name="PixY"></param> /// <param name="Ksi"></param> /// <param name="PixXDev"></param> /// <param name="PixYDev"></param> /// <param name="KsiDev"></param> /// <param name="distortion"></param> public static void GetPixelShape(EllipseParameter[] ellipse, ref double PixX, ref double PixY, ref double Ksi, ref double PixXDev, ref double PixYDev, ref double KsiDev, bool distortion) { for (int i = 0; i < ellipse.Length; i++) { ellipse[i].SetCoeff(); //RがRになるように調節する ellipse[i].Coeff[0] *= ellipse[i].millimeterCalc * ellipse[i].millimeterCalc / 1000000; ellipse[i].Coeff[1] *= ellipse[i].millimeterCalc * ellipse[i].millimeterCalc / 1000000; ellipse[i].Coeff[2] *= ellipse[i].millimeterCalc * ellipse[i].millimeterCalc / 1000000; } //半径Rの円 X^2 + Y^2 = R^2 がアフィン変換 { { A, B} , { 0 , C } } という行列で変換されると //楕円 a * X^2 + b * X * Y + c * Y^2 = X^2 / A^2 - X * Y * 2B /A^2/C + Y^2 * (A^2+B^2) /(A^2 C^2) = R^2 に変換される //このとき //A = 1 / √(a) //B = - b /√(a) /√(4ac-b^2) //C = 2√(a) /√(4ac-b^2) List <double> tempPixX = new List <double>(); List <double> tempPixY = new List <double>(); List <double> tempKsi = new List <double>(); double A, B, C; for (int i = 0; i < ellipse.Length; i++) { A = Math.Sqrt(1.0 / ellipse[i].Coeff[0]); B = -ellipse[i].Coeff[1] / Math.Sqrt(ellipse[i].Coeff[0] * (4 * ellipse[i].Coeff[0] * ellipse[i].Coeff[2] - ellipse[i].Coeff[1] * ellipse[i].Coeff[1])); C = 2 * Math.Sqrt(ellipse[i].Coeff[0] / (4 * ellipse[i].Coeff[0] * ellipse[i].Coeff[2] - ellipse[i].Coeff[1] * ellipse[i].Coeff[1])); //{ { A, B} , { 0 , C } } * {x, y} = { { PixX , PixY SinKsi } , { 0 , PixelY } } * {X,Y} // ただし {x,y}は真の円上の座標, {X,Y}はピクセル座標 //だから newPixX = PixX /A, newPixY = PixY /C, tan(newKsi) = C (tanKsi-B) /A tempPixX.Add(PixX / A); tempPixY.Add(PixY / C); tempKsi.Add(Math.Atan(C / A * (Math.Tan(Ksi) - B))); } PixX = tempPixX.Average(); PixXDev = Statistics.Deviation(tempPixX.ToArray()); PixY = tempPixY.Average(); PixYDev = Statistics.Deviation(tempPixY.ToArray()); if (distortion) { Ksi = tempKsi.Average(); KsiDev = Statistics.Deviation(tempKsi.ToArray()); } }
/// <summary> /// 一枚の写真中の複数のピークを同時に渡してその加重平均から波長と誤差を計算する (FindWaveLength2を内部的に呼び出す) /// </summary> /// <param name="p"></param> /// <param name="WaveLength"></param> /// <param name="WaveLengthDev"></param> public static void FindWaveLengthFromMultiPeaks(List <EllipseParameter> ellipses, ref double WaveLength, ref double WaveLengthDev) { if (ellipses == null || ellipses.Count < 1) { return; } double tempTotal = 0; double temp, sigma1, sigma2, weight; double weightTotal = 0; List <double> WL = new List <double>(); for (int i = 0; i < ellipses.Count; i++) { for (int j = i + 1; j < ellipses.Count; j++) { for (int k = 0; k < ellipses[i].millimeters.Count; k++) { if (!double.IsNaN(ellipses[i].millimeters[k]) && !double.IsNaN(ellipses[j].millimeters[k])) { double obs1 = ellipses[i].millimeters[k]; double obs2 = ellipses[j].millimeters[k]; double d1 = ellipses[i].d; double d2 = ellipses[j].d; temp = FindParameter.FindWaveLength2(obs1, obs2, d1, d2, WaveLength); sigma1 = (FindParameter.FindWaveLength2(obs1 + 0.1, obs2, d1, d2, WaveLength) - temp); sigma2 = (FindParameter.FindWaveLength2(obs1, obs2 + 0.1, d1, d2, WaveLength) - temp); if (sigma1 != 0 || sigma2 != 0) { weight = 1 / (sigma1 * sigma1 + sigma2 * sigma2); weightTotal += weight; tempTotal += weight * temp; WL.Add(temp); } } } } } if (weightTotal > 0 && !double.IsInfinity(weightTotal)) { WaveLength = tempTotal / weightTotal; WaveLengthDev = Statistics.Deviation(WL.ToArray()) / Math.Sqrt(Math.Sqrt(2 * WL.Count)); } }
/// <summary> /// 一枚の写真中の複数のピークと波長+カメラ長からピクセルサイズを計算する (全パターンからの算出) /// </summary> /// <param name="p"></param> /// <param name="WaveLength"></param> /// <param name="WaveLengthDev"></param> public static void FindPixelSizeFromMultiPeaks(List <Plane> plane, double CameraLength, double WaveLength, ref double PixelSize, ref double PixelSizeDev) { if (plane == null) { return; } double tempTotal = 0; double temp, sigma1, sigma2, weight; double weightTotal = 0; List <double> CL = new List <double>(); for (int i = 0; i < plane.Count; i++) { for (int j = i + 1; j < plane.Count; j++) { if (!double.IsNaN(plane[i].MillimeterObs) && !double.IsNaN(plane[j].MillimeterObs) && plane[i].IsFittingChecked && plane[j].IsFittingChecked) { double obs1 = plane[i].MillimeterObs; double obs2 = plane[j].MillimeterObs; double d1 = plane[i].d; double d2 = plane[j].d; temp = CameraLength * Math.Tan(2 * Math.Asin(GetSinTheta(obs1, obs2, d1, d2, WaveLength))) / obs1 * PixelSize; sigma1 = CameraLength * Math.Tan(2 * Math.Asin(GetSinTheta(obs1 + 0.1, obs2, d1, d2, WaveLength))) / obs1 * PixelSize - temp; sigma2 = CameraLength * Math.Tan(2 * Math.Asin(GetSinTheta(obs1, obs2 + 0.1, d1, d2, WaveLength))) / obs1 * PixelSize - temp; if (sigma1 != 0 || sigma2 != 0) { weight = 1 / (sigma1 * sigma1 + sigma2 * sigma2); weightTotal += weight; tempTotal += weight * temp; CL.Add(temp); } } } } if (weightTotal > 0 && !double.IsInfinity(weightTotal)) { PixelSize = tempTotal / weightTotal; PixelSizeDev = Statistics.Deviation(CL.ToArray()) / Math.Sqrt(Math.Sqrt(2 * CL.Count)); } }
/// <summary> /// 一枚の写真中の複数のピークを同時に渡してその加重平均から波長と誤差を計算する (FindWaveLength2を内部的に呼び出す) /// </summary> /// <param name="p"></param> /// <param name="WaveLength"></param> /// <param name="WaveLengthDev"></param> public static void FindWaveLengthFromMultiPeaks(List <Plane> plane, ref double WaveLength, ref double WaveLengthDev) { if (plane == null) { return; } double tempTotal = 0; double temp, sigma1, sigma2, weight; double weightTotal = 0; List <double> WL = new List <double>(); for (int i = 0; i < plane.Count; i++) { for (int j = i + 1; j < plane.Count; j++) { if (!double.IsNaN(plane[i].MillimeterObs) && !double.IsNaN(plane[j].MillimeterObs) && plane[i].IsFittingChecked && plane[j].IsFittingChecked) { double obs1 = plane[i].MillimeterObs; double obs2 = plane[j].MillimeterObs; double d1 = plane[i].d; double d2 = plane[j].d; temp = FindParameter.FindWaveLength2(obs1, obs2, d1, d2, WaveLength); sigma1 = (FindParameter.FindWaveLength2(obs1 + 0.1, obs2, d1, d2, WaveLength) - temp); sigma2 = (FindParameter.FindWaveLength2(obs1, obs2 + 0.1, d1, d2, WaveLength) - temp); if (sigma1 != 0 || sigma2 != 0) { weight = 1 / (sigma1 * sigma1 + sigma2 * sigma2); weightTotal += weight; tempTotal += weight * temp; WL.Add(temp); } } } } if (weightTotal > 0 && !double.IsInfinity(weightTotal)) { WaveLength = tempTotal / weightTotal; WaveLengthDev = Statistics.Deviation(WL.ToArray()) / Math.Sqrt(Math.Sqrt(2 * WL.Count)); } }
/// <summary> /// 2枚のフィルム距離の異なる画像からフィルム距離を返す。フィルム距離の差(誤差無し)が必要 /// </summary> /// <param name="p"></param> /// <param name="FilmDistanceDiscrepancy"></param> /// <param name="FilmDistance"></param> /// <param name="FilmDistanceDev"></param> public static void FindFilmDistanceFromDiscrepancy(List <Plane> plane1, List <Plane> plane2, double Discrepancy, ref double FilmDistance, ref double FilmDistanceDev) { List <double> FD = new List <double>(); double temp, dif1, dif2, weight; double tempTotal = 0; double weightTotal = 0; for (int i = 0; i < plane1.Count; i++) { for (int j = 0; j < plane2.Count; j++) { if (plane1[i].strHKL == plane2[j].strHKL && !double.IsNaN(plane1[i].MillimeterObs) && !double.IsNaN(plane2[j].MillimeterObs) && plane1[i].IsFittingChecked && plane2[j].IsFittingChecked) { double m1 = plane1[i].MillimeterObs; double m2 = plane2[j].MillimeterObs; temp = FindCameraLength(m1, m2, Discrepancy); dif1 = FindCameraLength(m1 + 0.1, m2, Discrepancy) - temp; dif2 = FindCameraLength(m1, m2 + 0.1, Discrepancy) - temp; weight = 1 / (dif1 * dif1 + dif2 * dif2) * 100; weightTotal += weight; tempTotal += weight * temp; FD.Add(temp); } } } if (weightTotal > 0 && !double.IsInfinity(weightTotal)) { FilmDistance = tempTotal / weightTotal; if (FD.Count > 1) { FilmDistanceDev = Statistics.Deviation(FD.ToArray()) / Math.Sqrt(FD.Count - 1); } else { FilmDistanceDev = 0; } } }
public static void FindSphericalCorrection(List <EllipseParameter> ellipses, double waveLength, double filmDistance, ref double radiusInverse, ref double radiusInverseDev) { double weightTotal = 0; double tempRtotal = 0; List <double> r = new List <double>(); for (int i = 0; i < ellipses.Count; i++) { for (int j = i + 1; j < ellipses.Count; j++) { for (int k = 0; k < ellipses[i].millimeters.Count; k++) { if (!double.IsNaN(ellipses[i].millimeters[k]) && !double.IsNaN(ellipses[j].millimeters[k])) { double obs1 = ellipses[i].millimeters[k]; double obs2 = ellipses[j].millimeters[k]; double d1 = ellipses[i].d; double d2 = ellipses[j].d; double tempR = FindParameter.FindSphericalCorrection(obs1, obs2, d1, d2, waveLength, filmDistance); double sigma1 = FindParameter.FindSphericalCorrection(obs1, obs2 + 0.01, d1, d2, waveLength, filmDistance) - tempR; if (sigma1 != 0) { weightTotal += 1 / (sigma1 * sigma1); tempRtotal += tempR / (sigma1 * sigma1); r.Add(tempR); } } } } } if (weightTotal > 0 && !double.IsInfinity(weightTotal)) { radiusInverse += tempRtotal / weightTotal; radiusInverseDev = Statistics.Deviation(r.ToArray()) / Math.Sqrt(Math.Sqrt(2 * r.Count)); } }
/// <summary> /// 2枚のフィルム距離の異なる画像からフィルム距離を返す。フィルム距離の差(誤差無し)が必要 /// </summary> /// <param name="p"></param> /// <param name="FilmDistanceDiscrepancy"></param> /// <param name="FilmDistance"></param> /// <param name="FilmDistanceDev"></param> public static void FindFilmDistanceFromDiscrepancy(List <EllipseParameter> ellipses1, List <EllipseParameter> ellipses2, double Discrepancy, ref double FilmDistance, ref double FilmDistanceDev) { List <double> FD = new List <double>(); double temp, dif1, dif2, weight; double tempTotal = 0; double weightTotal = 0; for (int i = 0; i < ellipses1.Count; i++) { for (int j = 0; j < ellipses2.Count; j++) { for (int k = 0; k < ellipses1[i].millimeters.Count; k++) { if (ellipses1[i].strHKL == ellipses2[j].strHKL && !double.IsNaN(ellipses1[i].millimeters[k]) && !double.IsNaN(ellipses2[j].millimeters[k])) { double m1 = ellipses1[i].millimeters[k]; double m2 = ellipses2[j].millimeters[k]; temp = FindCameraLength(m1, m2, Discrepancy); dif1 = FindCameraLength(m1 + 0.1, m2, Discrepancy) - temp; dif2 = FindCameraLength(m1, m2 + 0.1, Discrepancy) - temp; weight = 1 / (dif1 * dif1 + dif2 * dif2) * 100; weightTotal += weight; tempTotal += weight * temp; FD.Add(temp); } } } } if (weightTotal > 0 && !double.IsInfinity(weightTotal)) { FilmDistance = tempTotal / weightTotal; FilmDistanceDev = Statistics.Deviation(FD.ToArray()) / Math.Sqrt(FD.Count); } }
/// <summary> /// 固定されたピクセルサイズとフィルム距離から波長をかえす /// </summary> /// <param name="p"></param> /// <param name="PixelSize"></param> /// <param name="FilmDistance"></param> /// <param name="WaveLength"></param> /// <param name="WaveLengthDev"></param> public static void FindWaveLengthFromFixedPixelSize(List <EllipseParameter> ellipse, double FilmDistance, ref double WaveLength, ref double WaveLengthDev) { //int n = 0; double tempTotal = 0; double weightTotal = 0; double weight, temp, diff; List <double> WL = new List <double>(); for (int i = 0; i < ellipse.Count; i++) { temp = 2 * ellipse[i].d * Math.Sin(Math.Atan(ellipse[i].GetAverageRadius() / FilmDistance) / 2); diff = 2 * ellipse[i].d * Math.Sin(Math.Atan((ellipse[i].GetAverageRadius() + 0.1) / FilmDistance) / 2) - temp; weight = 1 / diff / diff; weightTotal += weight; tempTotal += weight * temp; WL.Add(temp); } if (weightTotal > 0 && !double.IsInfinity(weightTotal)) { WaveLength = tempTotal / weightTotal; WaveLengthDev = Statistics.Deviation(WL.ToArray()) / Math.Sqrt(WL.Count); } }