代码之家  ›  专栏  ›  技术社区  ›  esac

如何将矩形反转为Picasa面哈希

  •  4
  • esac  · 技术社区  · 14 年前

    以下是Picasa作为哈希存储的详细信息。它像这样存储它们:

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

    网上信息显示:

    rect64()中包含的数字是64位十六进制数字。

    • 把它分成四个16位数字。
    • 将每个数除以最大无符号16位数字(65535),您将得到4个介于0和1之间的数字。
    • 剩下的四个数字为面矩形提供了相对坐标:(左、上、右、下)。
    • 如果要以绝对坐标结尾,请按图像宽度和图像高度分别乘以左、右和上、下。

    所以我把它转换成矩形的代码工作得很好(只保留相对坐标):

        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);
        }
    

    现在我有一个矩形,我想把它转换回上面提到的散列。我好像搞不清楚。看起来picasa使用了2个字节,包括精度,但是c中的浮点值是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();
        }
    
    2 回复  |  直到 14 年前
        1
  •  1
  •   Dave    14 年前

    当前代码正在交换每个坐标的字节。这是因为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");
        }
    
        2
  •  0
  •   lmat - Reinstate Monica    14 年前

    看起来您需要从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);
    

    让我知道这是否有效!

    亚伦