• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Obrócenie zdjęcia powoduje zmianę jego wielkości

+3 głosów
174 wizyt
pytanie zadane 27 stycznia 2017 w Offtop przez kubekzone Użytkownik (610 p.)
edycja 27 stycznia 2017 przez kubekzone

Witam,

Podczas rutynowych czynności zauważyłem pewną ciekawostkę :D Otóż, zdjęcia które są dłuższe w poziomie są cięższe niż ich odpowiedniki postawione "do pionu". Na przykładzie:

 

 

 

 

Zdjęcie DSC_0097 waży 357KB, po "obróceniu w prawo" jego wielkość wynosi 278KB ! :O

Co dziwniejsze, po obróceniu w lewo (czyli do stanu wyjściowego) jego waga praktycznie się nie zmienia (wynosi 279KB).

Ktoś może mi to wytłumaczyć? :D To znaczna oszczędność miejsca, szczególnie jak sie ma masę zdjęć do wysłania komuś w archiwum.

Dodam jeszcze, że 7zip przy opcji "ultra" nie jest wstanie skompresować zdjęcia nawet w 50% tak jak to windows robi przy obracaniu :D

Przeglądarka zdjęć: domyślna windows, zdjęcia w rozszerzeniu JPEG, Windows 7 x64.

 

Update: Sprawdzałem na różnych zdjęciach, jedne zdjęcia zmniejszają swoją wielkość, inne zwiększają.

Po obrocie pewnego dość dużego zdjęcia (ponad 21MB, 9621x6613) jego rozmiar zmniejszył się o 6MB (sic!). Domyślam się, że windows pogorszył mi jego jakość... da się to jakoś cofnąć? indecision

3
komentarz 27 stycznia 2017 przez Gynvael Coldwind Stary wyjadacz (10,700 p.)
Ad Update:

Generalnie nie da się cofnąć, chyba, że Windows Ci robi automatycznie backupy. Wejdź we właściwości pliku i tam zakładka "Poprzednie wersje". Jeśli masz jakąś poprzednią wersję, to możesz po prostu ją przywrócić. Jeśli nie masz, to niestety nic z tego.
komentarz 27 stycznia 2017 przez kubekzone Użytkownik (610 p.)

Dzięki! Nawet nie wiedziałem, że windows robi mi takie backupy. Co ciekawe jedyna kopia zdjęcia była z 2012roku smiley Co jeszcze bardziej ciekawe, ta wersja waży 31MB (czyli ok 10MB więcej niż ta którą miałem dziś rano)

3 odpowiedzi

+10 głosów
odpowiedź 27 stycznia 2017 przez Gynvael Coldwind Stary wyjadacz (10,700 p.)
wybrane 31 stycznia 2017 przez kubekzone
 
Najlepsza

Ciekawy problem. Natomiast zaczął bym od tego, że chyba trochę za dużo zmiennych masz naraz w eksperymencie. Tj. wydaje mi się, że testujesz naraz dwie rzeczy:

1. Re-kompresje JPG innym enkoderem z innymi ustawieniami (np. oryginalnie plik mógł być zapisany z jakością na 100%, a Twój enkoder używa jakości np. 85%).
2. Obracanie.

Zrobiłem kilka eksperymentów eliminując punkt pierwszy, tj. wyszedłem od pliku PNG/JPG, obróciłem go o 90 stopni w prawo, w lewo, i zostawiłem również wersję zapisaną normalnie, po czym skonwertowałem trzy pliki tak uzyskane na JPG/PNG. Różnica oczywiście jest (co do tego "czemu" to przejdę za chwilę), natomiast jest niewielka:

Test 1 - wejściowy PNG ze screenshotem z konsoli, okolice 1000x750px:

wyjściowy jpeg nieobrócony: 347 547 bajtów
wyjściowy jpeg obrócony w prawo o 90°: 362 779 bajtów
wyjściowy jpeg obrócony w lewo o 90°: 355 249 bajtów
skrajna różnica (abs(najmniejszy / największy - 1)): ~5%

Test 2 - wejściowy JPG z tapetą 8K z BF4:

wyjściowy jpeg nieobrócony: 5 081 563 bajtów
wyjściowy jpeg obrócony w prawo o 90°: 5 084 279 bajtów
wyjściowy jpeg obrócony w lewo o 90°: 5 064 936 bajtów
skrajna różnica (abs(najmniejszy / największy - 1)): ~0.5%

Test 3 - ten sam plik co w pierwszym teście, ale zapisany do PNG z tymi samymi ustawieniami:

wyjściowy png nieobrócony: 84 708 bajtów
wyjściowy png obrócony w prawo o 90°: 101 784 bajtów
wyjściowy png obrócony w lewo o 90°: 102 492 bajtów
skrajna różnica (abs(najmniejszy / największy - 1)): ~20%

I teraz pozostaje zagadka czemu jest jakakolwiek różnica.

Generalnie sprowadza się to do tego jak działają algorytmy kompresujące użyte w danym formacie. Konkretniej, jeśli są użyte algorytmy, których skuteczność zależy od kolejności danych, to zmiana będzie widoczna (przykłady: cała rodzina LZ77/LZW/etc, RLE). Jeśli natomiast użyte algorytmy są agnostyczne względem kolejności danych (przykład: Huffman), to różnicy nie powinno być w ogóle.

Formaty graficzne zazwyczaj korzystają z kilku algorytmów. Przykładowo, PNG w którego przypadku różnica była największa korzysta z:

1. Przede wszystkim filtrów, które wykonują proste operacje matematyczne pomiędzy kolejnymi liniami (co ma na celu zmniejszyć entropię danych jeśli linie się między sobą nie różnią znacznie).
2. DEFLATE (czyli LZ77 + Huffman).

Więc w tym wypadku zarówno filtry jak i sam DEFLATE (z uwagi na LZ77) zareagują na obrót obrazka, ponieważ dane ułożą się w zupełnie inny sposób (np. podobne pionowo linie wcale nie muszą być podobne poziomo; albo vice versa).

Jeśli chodzi o JPEG to przyznaję, że znam słabiej ten format. Generalnie grafika jest dzielona na bloki 8x8 i one są oddawane dyskretnej transformacie cosinusowej. Jak dla mnie ten etap powinien wyglądać bardzo podobnie po obrocie, głównie dlatego że de facto zawartość bloków 8x8 się nie zmieni, a sama transformata *chyba* nie zależy od kolejności danych. Natomiast potem używany jest algorytm Huffmana, któremu kolejność danych nie robi różnicy. Natomiast różnica i tak jest (choć niewielka).
Może ktoś inny ma jakiś pomysł? :)

4
komentarz 27 stycznia 2017 przez Gynvael Coldwind Stary wyjadacz (10,700 p.)

Ciekawym problemem pochodnym jest stworzenie takiej bitmapy, by w danym formacie jej obrót dał największą różnicę. Pobawiłem się chwilę dla PNG i wyszło mi coś takiego:

 

http://gynvael.vexillium.org/ext/dump_3e.png
http://gynvael.vexillium.org/ext/dump_3e_rot.png (odwrócona o 90)

Ten pierwszy plik PNG ma 28280 bajtów, a ten drugi jedyne 1632 bajty.

Generalnie skupiłem się na takim wygenerowaniu bitmapy by przeciwdziałać filtrom PNG, tj. żeby pionowa i pozioma reprezentacja po przefiltrowaniu dała największą różnice w entropii. Skrypt do wygenerowania (convert pochodzi z pakietu ImageMagick; najlepsze rezultaty są dla 0x3e i 0x3f, chociaż warto by pewnie puścić na pełnym zakresie):

import random, os

d = bytearray(os.urandom(128 * 3))

def go(ff, d):
  f = open("dump.raw", "wb")
  for i in range(128):
    for j in range(128 * 3):
      if j % 2 == 0:
        d[j] = (d[j]+ff) & 0xff
      else:
        d[j] = (d[j]-ff) & 0xff
    f.write(str(d))
  f.close()

  os.system("convert -depth 8 -size 128x128 rgb:dump.raw x/dump_%.2x.png" % (ff))
  os.system("convert -rotate 90 -depth 8 -size 128x128 rgb:dump.raw x/dump_%.2x_rot.png" % (ff))  

for x in range(64):
  print "      %i      \r" % x,
  k = d[:]
  go(x, k)

Jeśli komuś udałoby się wygenerować coś ciekawszego (tj. z jeszcze większą różnicą niż 17.32x), to dajcie znać plz :)

komentarz 30 stycznia 2017 przez efiku Maniak (74,980 p.)
Jak dla mnie naj odpowiedź ;D

Witamy na forum :V
komentarz 4 czerwca przez Gynvael Coldwind Stary wyjadacz (10,700 p.)
Po dwóch latach wróciłem do tego przykładu i okazało się, że mój przykład jest błędny.

Konkretniej - okazuje się, że filtry w PNG są dobrze zaprojetowane i bardzo dobrze sobie radzą z zależnościami między pixelami zarówno w pionie jak i w poziomie. Jak pisałem poprzedni komentarz, to zapomniałem o tym "w poziomie" i napisałem kod, który to "nadużywał". I jak pisałem, to zadziałało (co de facto mnie zmyliło).

OK, dlaczego więc mój przykład działał? Bo okazuje się, że sporo encoderów PNG ma problem ze znalezieniem zależności między pixelami w pionie (tu chyba miałem kolejny błąd, bo jednak zakładałem, że problem jest "w poziomie") i nie używa odpowiednich filtrów, przez co pliki wychodzą przesadnie duże, mimo, że nie muszą.

Po użyciu odpowiedniego encodera PNG (który radzi sobie z zależnościami w pionie) oba pliki wychodzą mniej więcej tego samego rozmiaru (w okolicach 1k).

Póki co jestem zdania, że filtrów nie można oszukać, i żeby wykazać ten efekt zmiany wielkości po obrocie trzeba jednak skupić się na niższych warstwach kompresji (DEFLATE).

Oh well.
0 głosów
odpowiedź 27 stycznia 2017 przez Borówa Dyskutant (8,070 p.)
Jeśli to prawda to dziwne. U mnie nie działa takie coś, obojętnie jak obrócę rozmiar pozostaje ten sam niezależnie od rozmiaru zdjęcia. Może to bug?
komentarz 27 stycznia 2017 przez kubekzone Użytkownik (610 p.)
Raczej nie bug, sprawdziłem na innym komputerze i każde zdjęcie (które obracałem) zmieniało swój rozmiar o pewną ilość bajtów. Niestety zauważyłem, że niektóre zdjęcia zwiększały swój rozmiar i już nie dało się wrócić do ich pierwotnego rozmiaru :c

Podobne pytania

+1 głos
3 odpowiedzi 245 wizyt
0 głosów
1 odpowiedź 71 wizyt
pytanie zadane 17 października 2015 w JavaScript, jQuery, AJAX przez Paweł123 Nałogowiec (29,570 p.)
0 głosów
3 odpowiedzi 497 wizyt
Porady nie od parady
Pytania na temat serwisu SPOJ należy zadawać z odpowiednią kategorią dotyczącą tej strony.SPOJ

64,865 zapytań

111,326 odpowiedzi

234,207 komentarzy

46,727 pasjonatów

Przeglądających: 207
Pasjonatów: 11 Gości: 196

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...