2016-08-31 3 views
1

EmguCVライブラリで実行されたカメラのキャリブレーションは、画像にキャリブレーションを適用することができ、少なくともいくらか修正されているように見えます。今私はプログラムを実行するときに単に読み込むことができるようにディスクに校正を保存したい。 IntrinsicCameraParametersには、引数としてXmlWriterとXmlReaderをそれぞれとるwriteXML()とreadXML()というメソッドがあります。行く道のように思える。誰かがデフォルトのXmlWriterをインスタンス化し、直ちにそれを使ってWriteXml()を呼び出す例が見つかりました。しかし、これを試してみると、XMLの構造に関連しているようなランタイム例外が発生します(つまり、XML内に1つのルートノードしか持つことができません)。だから私はコードを調整し、それを下に共有しました。私が愚かなルート要素を含んでいなければ、 "WriteXml"を呼び出すと、不適切に形成されたXMLに関する例外がスローされます。だから、私はそれを書くことができるようだが、私はそれを読む方法を知らない。おそらく、愚かなルート要素は、読み込みが成功するのを妨げるでしょう。それを読んだ人の例は見つけられません。誰かが共有する例がありますか?IntrinsicCameraParametersをXMLで保存/ロードする方法

public void SaveCalibrationToFile(IntrinsicCameraParameters ICP) 
     { 
      XmlWriterSettings settings = new XmlWriterSettings(); 
      settings.ConformanceLevel = ConformanceLevel.Auto; 

      // DISTORTION COEFFICIENTS 
      XmlWriter writer = XmlWriter.Create("C:\\Video\\Cal\\DistortionCoeff.xml", settings);    
      writer.WriteStartDocument(); 
      writer.WriteStartElement("TheStupidRootElement"); 

       writer.WriteStartElement("TheDistortionCoefficients"); 
       ICP.DistortionCoeffs.WriteXml(writer); 
       writer.WriteEndElement(); // end TheDistortionCoefficients 

      writer.WriteEndElement(); // end TheStupidRootElement 
      writer.WriteEndDocument(); 
      writer.Close(); 

      // CAMERA MATRIX 
      writer = XmlWriter.Create("C:\\Video\\Cal\\CameraMatrix.xml", settings);     
      writer.WriteStartDocument(); 
      writer.WriteStartElement("TheStupidRootElement"); 

       writer.WriteStartElement("TheCameraMatrix"); 
       ICP.IntrinsicMatrix.WriteXml(writer); 
       writer.WriteEndElement(); // end TheCameraMatrix 

      writer.WriteEndElement(); // end TheStupidRootElement 
      writer.WriteEndDocument(); 
      writer.Close(); 

      // now [just to see if it worked] try to load from the XML 
      XmlReaderSettings readerSettings = new XmlReaderSettings(); 
      readerSettings.ConformanceLevel = ConformanceLevel.Auto; 
      XmlReader reader = XmlReader.Create("C:\\Video\\Cal\\DistortionCoeff.xml", readerSettings); 

      IntrinsicCameraParameters ICP_read = new IntrinsicCameraParameters(); 
      IC.DistortionCoeffs.ReadXml(reader);     
     } 
+0

[ 'IntrinsicCameraParameters.DistortionCoeffs'(http://www.emgu.com/wiki/files/2.0.0.0/html /ecc3c8f8-9f92-10b1-96a2-b0b1ca6501e9.htm)は実際に['IXmlSerializable'](https://msdn2.microsoft.com/en-us/library/fhd7bk0a)を実装しているので、単純に[' XmlSerializer' ](IntrinsicCameraParameters')(https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer(v = vs.110).aspx)の[http://www.emgu .com/wiki/files/2.0.0.0/html/1ad4e83e-3c4b-d128-cd44-c9e8a9da007f.htm)? – dbc

+0

私はそれを試していません。私はXMLにあまりよく似ていません。 XmlSerializerの使用方法を詳しく説明できますか? –

答えて

1

は、.NETが自動的にパブリックプロパティの反射を介したからとXMLへの型のインスタンスをシリアル化できるクラスXmlSerializerが含まれています。また、IXmlSerializableインターフェイスをサポートしているため、型のデフォルト動作をオーバーライドし、XMLへのシリアル化の仕方を完全に制御できます。

このように、IntrinsicCameraParameters.IntrinsicMatrixおよびIntrinsicCameraParameters.DistortionCoeffsは両方ともタイプMatrix<double>であり、基底クラスCvArray<TDepth>はこのインターフェイスを実装しています。したがって、このタイプのオブジェクトは、次の拡張メソッドを使用してXmlSerializerを使用してXMLにシリアライズする必要があります:

public static partial class XmlSerializationExtensions 
{ 
    public static void SerializeToXmlFile<T>(this T obj, string fileName) 
    { 
     var settings = new XmlWriterSettings { Indent = true }; 
     using (var writer = XmlWriter.Create(fileName, settings)) 
     { 
      new XmlSerializer(typeof(T)).Serialize(writer, obj); 
     } 
    } 

    public static T DeserializeFromXmlFile<T>(string fileName) 
    { 
     using (var reader = XmlReader.Create(fileName)) 
     { 
      return (T)new XmlSerializer(typeof(T)).Deserialize(reader); 
     } 
    } 
} 

次に、あなただけの行うことができます。

var fileName = "C:\\Video\\Cal\\CameraMatrix.xml"; 
ICP.IntrinsicMatrix.SerializeToXmlFile(fileName); 

以降、行う、戻ってそれを読むために:

var newIntrinsicMatrix = XmlSerializationExtensions.DeserializeFromXmlFile<Matrix<double>>(fileName); 

確認のため、XMLとの間で行列をシリアル化する別の例については、the documentationを参照してください。

論理的には、また、同じジェネリック拡張メソッドを使用して単一のXMLファイルにIntrinsicCameraParameters全体を保存し、復元することが可能なはずである。

ICP.SerializeToXmlFile(fileName); 

は残念ながら、問題があります。 CvArray<TDepth>ReadXml()の実装が壊れています。 Proper way to implement IXmlSerializable?

からReadXmlの説明の方法は がWriteXmlメソッドによって書かれたとの情報を使用して あなたのオブジェクトを再構築しなければなりません。

このメソッドを呼び出すと、リーダー は、タイプ の情報をラップする 要素の先頭に配置されます。すなわち、 開始タグの直前で、 のシリアル化されたオブジェクトの開始を示します。この メソッドが返された場合、その要素のすべてを含む の最初から最後まで、要素全体を で読み取る必要があります。 WriteXmlメソッド とは異なり、フレームワーク はラッパー要素 を自動的に処理しません。あなたの実装は でなければなりません。これらの 位置決めルールを守らないと、 に予期しないランタイム例外 が生成されるか、データが破損する可能性があります。

そしてCvArray<TDepth>ためsource codeのクイックチェックは、ラッパー要素の終わりはを読んでいないであることを示しています。これにより、XML内の最初のCvArray<>に続くデータはすべてデシリアライズされなくなります。

したがって、Matrix<T>を大きなXMLファイルに埋め込みたい場合は、次のように、シリアライズサロゲートタイプ(またはデータ転送オブジェクトタイプ)を導入する必要があります。 (Emgu.CV.SerializationSurrogates名前空間の導入に注意してください):

namespace Emgu.CV.SerializationSurrogates 
{ 
    using Emgu.CV; 

    public class Matix<TDepth> where TDepth : new() 
    { 
     [XmlAttribute] 
     public int Rows { get; set; } 

     [XmlAttribute] 
     public int Cols { get; set; } 

     [XmlAttribute] 
     public int NumberOfChannels { get; set; } 

     [XmlAttribute] 
     public int CompressionRatio { get; set; } 

     public byte[] Bytes { get; set; } 

     public static implicit operator Emgu.CV.SerializationSurrogates.Matix<TDepth>(Emgu.CV.Matrix<TDepth> matrix) 
     { 
      if (matrix == null) 
       return null; 
      return new Matix<TDepth> 
      { 
       Rows = matrix.Rows, 
       Cols = matrix.Cols, 
       NumberOfChannels = matrix.NumberOfChannels, 
       CompressionRatio = matrix.SerializationCompressionRatio, 
       Bytes = matrix.Bytes, 
      }; 
     } 

     public static implicit operator Emgu.CV.Matrix<TDepth>(Matix<TDepth> surrogate) 
     { 
      if (surrogate == null) 
       return null; 
      var matrix = new Emgu.CV.Matrix<TDepth>(surrogate.Rows, surrogate.Cols, surrogate.NumberOfChannels); 
      matrix.SerializationCompressionRatio = surrogate.CompressionRatio; 
      matrix.Bytes = surrogate.Bytes; 
      return matrix; 
     } 
    } 

    public class IntrinsicCameraParameters 
    { 
     [XmlElement("IntrinsicMatrix", Type = typeof(Emgu.CV.SerializationSurrogates.Matix<double>))] 
     public Emgu.CV.Matrix<double> IntrinsicMatrix { get; set; } 

     [XmlElement("DistortionCoeffs", Type = typeof(Emgu.CV.SerializationSurrogates.Matix<double>))] 
     public Emgu.CV.Matrix<double> DistortionCoeffs { get; set; } 

     public static implicit operator Emgu.CV.SerializationSurrogates.IntrinsicCameraParameters(Emgu.CV.IntrinsicCameraParameters icp) 
     { 
      if (icp == null) 
       return null; 
      return new IntrinsicCameraParameters 
      { 
       DistortionCoeffs = icp.DistortionCoeffs, 
       IntrinsicMatrix = icp.IntrinsicMatrix, 
      }; 
     } 

     public static implicit operator Emgu.CV.IntrinsicCameraParameters(Emgu.CV.SerializationSurrogates.IntrinsicCameraParameters surrogate) 
     { 
      if (surrogate == null) 
       return null; 
      return new Emgu.CV.IntrinsicCameraParameters 
      { 
       DistortionCoeffs = surrogate.DistortionCoeffs, 
       IntrinsicMatrix = surrogate.IntrinsicMatrix, 
      }; 
     } 
    } 
} 

今、あなたは、次の拡張メソッドを使用してIntrinsicCameraParametersを保存し、取得することができます。

public static class IntrinsicCameraParametersExtensions 
{ 
    public static void SerializeIntrinsicCameraParametersExtensionsToXmlFile(this IntrinsicCameraParameters icp, string fileName) 
    { 
     var surrogate = (Emgu.CV.SerializationSurrogates.IntrinsicCameraParameters)icp; 
     surrogate.SerializeToXmlFile(fileName); 
    } 

    public static IntrinsicCameraParameters DeserializeIntrinsicCameraParametersFromXmlFile(string fileName) 
    { 
     var surrogate = XmlSerializationExtensions.DeserializeFromXmlFile<Emgu.CV.SerializationSurrogates.IntrinsicCameraParameters>(fileName); 
     return surrogate; 
    } 
} 

すべてはIntrinsicCameraParametersは、現在のリリースではmarked as obsoleteで、言われています:

[SerializableAttribute] 
[ObsoleteAttribute("This class will be removed in the next release, please use separate camera matrix and distortion coefficient with the CvInvoke function instead.")] 
public class IntrinsicCameraParameters : IEquatable<IntrinsicCameraParameters> 

このデザインを考え直すとよいでしょう。なお

CvArray<TDepth>.ReadXml()の非破損バージョンのようになり:

public virtual void ReadXml(System.Xml.XmlReader reader) 
    { 
     #region read properties of the matrix and assign storage 

     int rows = Int32.Parse(reader.GetAttribute("Rows")); // Should really be using XmlConvert for this 
     int cols = Int32.Parse(reader.GetAttribute("Cols")); 
     int numberOfChannels = Int32.Parse(reader.GetAttribute("NumberOfChannels")); 
     SerializationCompressionRatio = Int32.Parse(reader.GetAttribute("CompressionRatio")); 

     AllocateData(rows, cols, numberOfChannels); 

     #endregion 

     #region decode the data from Xml and assign the value to the matrix 

     if (!reader.IsEmptyElement) 
     { 
      using (var subReader = reader.ReadSubtree()) 
      { 
       // Using ReadSubtree guarantees we don't read past the end of the element in case the <Bytes> element 
       // is missing or extra unexpected elements are included. 
       if (subReader.ReadToFollowing("Bytes")) 
       { 
        int size = _sizeOfElement * ManagedArray.Length; 
        if (SerializationCompressionRatio == 0) 
        { 
         Byte[] bytes = new Byte[size]; 
         subReader.ReadElementContentAsBase64(bytes, 0, bytes.Length); 
         Bytes = bytes; 
        } 
        else 
        { 
         int extraHeaderBytes = 20000; 
         Byte[] bytes = new Byte[size + extraHeaderBytes]; 
         int countOfBytesRead = subReader.ReadElementContentAsBase64(bytes, 0, bytes.Length); 
         Array.Resize<Byte>(ref bytes, countOfBytesRead); 
         Bytes = bytes; 
        } 
       } 
      } 
     } 
     // Consume the end of the wrapper element also. 
     reader.Read(); 

     #endregion 
    } 
+1

この回答に記入していただきありがとうございます。私はあなたの以前の[今すぐ削除された]回答から2ファイルの解決策を手に入れました。私は1ファイルの将来を保証するソリューションに到達するまでに、さらに時間を費やしたくありません。 C#ツールは単なるテストベッドであり、最終的に私が作成しているものはC++の標準OpenCVで実装されます。私はEmguが混乱しているように感じ、OpenCVでOpenCVを使って作業しようとしていることさえも、まずは悪い考えだったかもしれません。私はそれがC#だから簡単だと思っていたが、私は今一週間これで終わっている。私の同僚は2日ほどPythonで同じことを書きました。 –

関連する問題