4

Picasa がハッシュとして保存するものの詳細は次のとおりです。次のように保存します。

faces=rect64(54391dc9b6a76c2b),4cd643f64b715489
[DSC_2289.jpg]
faces=rect64(1680000a5c26c82),76bc8d8d518750bc

Web 上の情報には次のように書かれています。

rect64() に含まれる数値は、64 ビットの 16 進数です。

  • それを 4 つの 16 ビットの数値に分割します。
  • それぞれを符号なし 16 ビットの最大数 (65535) で割ると、0 から 1 までの 4 つの数値が得られます。
  • 残りの 4 つの数値は、顔の四角形の相対座標 (左、上、右、下) を示します。
  • 絶対座標で終わらせたい場合は、左右に画像の幅を掛け、上下に画像の高さを掛けます。

したがって、それを RectangleF に変換する私のコードは問題なく動作します(相対座標のみを保持します):

    public static RectangleF GetRectangle(string hashstr)
    {
        UInt64 hash = UInt64.Parse(hashstr, System.Globalization.NumberStyles.HexNumber);
        byte[] bytes = BitConverter.GetBytes(hash);

        UInt16 l16 = BitConverter.ToUInt16(bytes, 6);
        UInt16 t16 = BitConverter.ToUInt16(bytes, 4);
        UInt16 r16 = BitConverter.ToUInt16(bytes, 2);
        UInt16 b16 = BitConverter.ToUInt16(bytes, 0);

        float left = l16 / 65535.0F;
        float top = t16 / 65535.0F;
        float right = r16 / 65535.0F;
        float bottom = b16 / 65535.0F;

        return new RectangleF(left, top, right - left, bottom - top);
    }

これで RectangleF ができたので、それを上記のハッシュに戻したいと思います。私はこれを理解できないようです。picasa は精度を含めて 2 バイトを使用しているように見えますが、C# の float は 8 バイトであり、BitConverter.ToSingle でさえ 4 バイトです。

どんな助けでも感謝します。

編集:これが私が今持っているものです

    public static string HashFromRectangle(RectangleCoordinates rect)
    {
        Console.WriteLine("{0} {1} {2} {3}", rect.Left, rect.Top, rect.Right, rect.Bottom);
        UInt16 left = Convert.ToUInt16((float)rect.Left * 65535.0F);
        UInt16 top = Convert.ToUInt16((float)rect.Top * 65535.0F);
        UInt16 right = Convert.ToUInt16((float)rect.Right * 65535.0F);
        UInt16 bottom = Convert.ToUInt16((float)rect.Bottom * 65535.0F);            

        byte[] lb = BitConverter.GetBytes(left);
        byte[] tb = BitConverter.GetBytes(top);
        byte[] rb = BitConverter.GetBytes(right);
        byte[] bb = BitConverter.GetBytes(bottom);

        byte[] barray = new byte[8];
        barray[0] = lb[0];
        barray[1] = lb[1];
        barray[2] = tb[0];
        barray[3] = tb[1];
        barray[4] = rb[0];
        barray[5] = rb[1];
        barray[6] = bb[0];
        barray[7] = bb[1];

        return BitConverter.ToString(barray).Replace("-", "").ToLower();
    }
4

2 に答える 2

1

現在のコードは、各座標のバイトを交換しています。これは、BitConverter がリトル エンディアン順でバイトを提供するためです (つまり、配列の最初のバイトが最下位バイトです)。次のように割り当てを交換すると、デコードと再エンコードで元のハッシュが返されます。

        barray[0] = lb[1];
        barray[1] = lb[0];
        barray[2] = tb[1];
        barray[3] = tb[0];
        barray[4] = rb[1];
        barray[5] = rb[0];
        barray[6] = bb[1];
        barray[7] = bb[0];

そうは言っても、単純な乗算と加算を使用して変換を行う方が明確だと思います。ulongハッシュ文字列を単一として読み込んで減算/除算すると、ハッシュ文字列のデコードで同様のことができます。たとえば、エンコーディングの場合:

    public static ushort ToUShort(double coordinate)
    {
        double ratio = Math.Max(0, Math.Min(Math.Round(coordinate * 65535), 65535));
        return (ushort)ratio;
    }

    public static string HashFromRectangle(Rect rect)
    {
        ulong left = ToUShort(rect.Left);
        ulong top = ToUShort(rect.Top);
        ulong right = ToUShort(rect.Right);
        ulong bottom = ToUShort(rect.Bottom);

        ulong hash = (((left * 65536) + top) * 65536 + right) * 65536 + bottom;
        return hash.ToString("x");
    }
于 2010-02-08T07:02:19.313 に答える
0

次のように HashFromRectangle(rect) から float 型を取り出す必要があるようです。

    UInt16 left = (UInt16)( rect.Left * 65535.0F);
    UInt16 top =(UInt16) (rect.Top * 65535.0F);
    UInt16 right = (UInt16) (rect.Right * 65535.0F);
    UInt16 bottom = (UInt16) (rect.Bottom * 65535.0F);

また、配列を埋めるためにこれを使用する方が読みやすいかもしれません:

    Array.Copy(lb, 0, barray, 0, 2);
    Array.Copy(tb, 0, barray, 2, 2);
    Array.Copy(rb, 0, barray, 4, 2);
    Array.Copy(bb, 0, barray, 6, 2);

これがうまくいくかどうか教えてください!

アーロン

于 2010-02-05T19:20:51.530 に答える