2010-02-04 2 views
4

Ниже приведены сведения о том, что Picasa хранит как хэш. Он хранит их, как это:Как отменить RectangleF на грань лица Picasa

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

Информация в Интернете говорит, что это:

Количество заключенное в rect64() представляет собой 64-разрядное шестнадцатеричное число.

  • Перерыв на четыре 16-разрядных номера.
  • Разделите каждый на максимальное неподписанное 16-битное число (65535), и у вас будет четыре цифры между 0 и 1.
  • Остальные четыре цифры дают относительные координаты для прямоугольника лица: (слева, сверху, вправо , дно).
  • Если вы хотите получить абсолютные координаты, несколько слева и справа по ширине изображения, а сверху и снизу - высота изображения.

Так что мой код, чтобы превратить это в 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 байта, включая точность, однако float в C# составляет 8 байтов, и даже битконвертер. ToSingle - 4 байта.

Любая помощь приветствуется.

EDIT: Вот то, что я прямо сейчас

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(); 
    } 
+0

Как нет с плавающей точкой типа данных с 2-мя байтами (в C# http://www.techotopia.com/index.php/C_Sharp_Variables_and_Constants), вы можете попробовать преобразовать его в короткий вместо , Преобразование должно быть явным (http://msdn.microsoft.com/en-us/library/ybs77ex4%28VS.71%29.aspx), иначе компилятор выдаст ошибку. – keyboardP

+0

Я тоже это пробовал, но мой хэш никуда не годится.Я отправляю свой код выше, чтобы увидеть, что я делаю что-то явно неправильно. – esac

ответ

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"); 
    } 
+0

Спасибо, кажется, теряют немного точности, но это делает это правильно. – esac

0

Похоже, что вам нужно вынимать типы с плавающей запятой от HashFromRectangle (Rect) как так:

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

Сообщите мне, если это работает!

Аарон

+0

К сожалению, нет. Я проверил это на известном хэше 1cf0102160008916. Оказывается хэш ff2983393f520976 и обращается к неправильным координатам. – esac

Смежные вопросы