android - usos - Las imágenes JPEG tienen diferentes valores de píxeles en múltiples dispositivos
mapa de bits usos (6)
Me había dado cuenta de que al leer una fotografía idéntica en dispositivos en formato JPEG, los valores de los píxeles no coinciden. Están cerca, pero son diferentes. Cuando se convierten a archivos PNG, los valores de los píxeles parecen coincidir.
Esto parece que se debería a los algoritmos de (des) compresión en los dispositivos. Eso es lo que viene a la mente de todos modos. ¿Hay alguna forma de leer en archivos JPEG para que los mismos píxeles se recuperen de la fotografía en todos los dispositivos? No veo una opción dentro del componente Opciones de BitmapFactory.
Actualmente se aplica lo siguiente para mantener el tamaño cuando se trabaja en valores de píxeles de una imagen en dispositivos:
Options options = new Options();
options.inScaled = false;
options.inPreferQualityOverSpeed = true;
Actualmente, comparamos los píxeles con los siguientes solo para ver algunos (concordancias cercanas, pero no iguales):
int[] pixels = new int[bitmapF.getWidth() * bitmapF.getHeight()];
bitmapF.getPixels(pixels, 0, bitmapF.getWidth(), 0, 0, bitmapF.getWidth(), bitmapF.getHeight());
Log.d("pixel entries", "pixels = " + pixels[233] + " - " + pixels[4002] + " - " + pixels[11391]);
Nota: si se lee en una versión PNG de ese mismo archivo que no está comprimido, los valores son idénticos a los esperados.
El Samsung Galaxy S4, por ejemplo, y el Samsung Galaxy S5, incluso tienen píxeles diferentes del mismo jpeg (que se ejecuta en la misma actividad de prueba) almacenados en la carpeta de activos.
El píxel [233], por ejemplo, sería -5205635 en s5 pero -5336451 en s4. El píxel [4002] también está un poco apagado. Pero el píxel [11391] es igual en ambos dispositivos en esta imagen jpeg.
Cambie el tamaño del medio al tamaño requerido o use los atributos HTML para deshabilitar la escala de la imagen.
Otra opción sería permitir que el usuario decida después de cargar una representación en miniatura para ahorrar ancho de banda.
El estándar JPEG no requiere que las implementaciones del decodificador produzcan imágenes de salida idénticas bit a bit. Desafortunadamente, el documento de estándares que especifica los requisitos del decodificador, ISO 10918-2 , aparentemente no está disponible gratuitamente en línea, pero Wikipedia dice :
... el estándar JPEG (y los estándares MPEG similares) incluye algunos requisitos de precisión para la decodificación, incluidas todas las partes del proceso de decodificación (decodificación de longitud variable, DCT inversa, descuantificación, renormalización de salidas); la salida del algoritmo de referencia no debe exceder:
- un máximo de 1 bit de diferencia para cada componente de píxel
- bajo error cuadrático medio en cada bloque de 8 × 8 píxeles
- [etc.]
Las diferencias entre las diferentes salidas del decodificador que usan la misma entrada generalmente se deben a los diferentes niveles de precisión interna, particularmente al realizar el IDCT. Otra posible fuente de diferencias es el suavizado, que intenta reducir los artefactos de "bloqueo".
Al igual que usted, esperaría que la configuración de inPreferQualityOverSpeed
produzca el mismo resultado, pero nada garantiza realmente eso. Puedo pensar en al menos un par de maneras en que podrías obtener pequeñas variaciones en dos teléfonos diferentes:
- Los teléfonos pueden ejecutar diferentes versiones de Android en las que se
BitmapFactory
la implementación deBitmapFactory
(por ejemplo, tal vezinPreferQualityOverSpeed
se rompió y luego seinPreferQualityOverSpeed
, o viceversa), o - Los teléfonos pueden proporcionar diferentes características de hardware (por ejemplo, conjunto de instrucciones vectoriales, coprocesador DSP, etc.) que aprovecha
BitmapFactory
. Incluso las diferencias en las unidades de punto flotante escalar pueden causar discrepancias, especialmente con la compilación JIT que produce las instrucciones reales de la máquina.
Dado el margen de maniobra en el estándar más sus observaciones experimentales, parece que la única forma de garantizar el acuerdo de bit por bit es realizar la decodificación dentro de su propia aplicación. Quizás puedas encontrar alguna biblioteca alternativa compatible con Android.
Estaba teniendo el mismo problema. Las imágenes PNG y JPEG parecen ser renderizadas con aproximación por diferentes dispositivos. Resolvimos el problema utilizando imágenes BMP (cuyas dimensiones son, lamentablemente, mucho más grandes).
Gran parte del trabajo de un decodificador JPEG involucra cálculos de números reales. Por lo general, esto se hace utilizando aritmética de enteros de punto fijo para el rendimiento. Esto introduce errores de redondeo. Las variaciones leves son una parte natural del trabajo con JPEG.
Sí, los valores de color de los píxeles son diferentes entre los dispositivos. Esto es muy molesto, especialmente si quieres comparar colores. La solución es comparar colores visualmente iguales (por percepción humana).
Uno de los mejores métodos para comparar dos colores según la percepción humana es CIE76. La diferencia se llama Delta-E. Cuando es menor que 1, el ojo humano no puede reconocer la diferencia.
Puede encontrar la maravillosa clase de utilidades de color ( ColorUtils ), que incluye los métodos de comparación CIE76. Está escrito por Daniel Strebel, de la Universidad de Zurich.
Desde ColorUtils.class utilizo el método:
static double colorDifference(int r1, int g1, int b1, int r2, int g2, int b2)
r1, g1, b1 - valores RGB del primer color
r2, g2, b2: valores RGB del segundo color que desea comparar
Si trabajas con Android, puedes obtener estos valores como este:
r1 = Color.red(pixel);
g1 = Color.green(pixel);
b1 = Color.blue(pixel);
Supongo que también debería comprobar si los PNG comprimidos aparecen de la misma manera en todos los dispositivos.
Si la respuesta es sí, lo único que quedaría sería averiguar cómo convertir esas imágenes a ese mismo tipo de png comprimido mediante programación en el teléfono.