8 puan yazan GN⁺ 2026-06-02 | 2 yorum | WhatsApp'ta paylaş
  • 8 bit tamsayı renkleri kayan noktalıya dönüştürürken 255’e bölme temelli standart yöntem ile 0.5 bias ekleyip 256’ya bölme temelli alternatif yöntem arasındaki fark
  • 255 yöntemi, tamsayı 0’ı 0.0’a, 255’i 1.0’a eşleyerek siyah ve beyazı doğrudan işlemeyi kolaylaştırır ve GPU’nun UNORM-to-float dönüşüm biçimiyle de uyumludur
  • 256 yöntemi, (img + 0.5) / 256.0 ile her değeri aralığın merkezine yerleştirir; bu, dithering gibi işlemlerde sınır durumlarını basitleştirebilir, ancak 0 artık 0.0 olmadığı için işleme mantığı 8 bit girdiye bağlı hale gelir
  • 255 yönteminde uçlardaki aralıklar yarım genişliktedir; bu yüzden tekdüze [0, 1] rastgele sayılar yeniden 8 bite yuvarlandığında 0 ve 255, diğer değerlerin yarısı sıklıkta ortaya çıkar; yine de gerçek görüntü ileri-geri dönüşümü kayıpsız çalışır
  • Başkasından gelen bir görseli işleyecekseniz doğru tercih 255 ile normalize etmek; yalnızca kaydetme ve yüklemeyi tamamen kontrol ettiğiniz durumlarda 256 yöntemi düşünülebilir

Problemin kurulumu

  • Bir görüntüyü alıp kayan noktalıya dönüştüren, işledikten sonra tekrar 8 bit renk olarak kaydeden bir programda tamsayı-kayan nokta dönüşüm yöntemi tartışma konusudur
  • İki yaklaşım vardır
    • Standart yöntem (255’e bölme): pixels = img / 255.0 → işleme → output = np.trunc(result * 255 + 0.5)
    • Alternatif yöntem (256’ya bölme): pixels = (img + 0.5) / 256.0 → işleme → output = np.trunc(result * 256)
    • Her iki durumda da son tür dönüşümünden önce değerler 0~255 aralığına sınırlandırılır: output.clip(0, 255).astype(np.uint8)
  • Standart yöntem, tamsayı 0’ı 0.0’a ve 255’i 1.0’a eşler; GPU’nun UNORM-to-float dönüşümü ile aynıdır
  • Alternatif yöntem 0.5 bias ekler; böylece tamsayı 0, 0.5/256 = 0.001953125 değerine eşlenir
    • Bunun sonucu olarak bu sabiti bilmiyorsanız siyah pikselleri tespit edemezsiniz
    • Kayan noktalı hesap yapsanız bile mantık 8 bit girdiye bağlı kalır
    • Standart yöntemde siyahın her zaman 0.0 olduğu varsayılabilir

255.0’a yönelik itirazlar

  • Standart yöntem sayı doğrusu üzerinde çizildiğinde biraz tuhaf görünür
  • İki uçta daha küçük kutular (bin) vardır

    • Standart formülün iki uçtaki kutuları [0,1] aralığının dışına taşar; aralık gerilmiş gibi görünür
    • Kayan noktalıyı tekrar tamsayıya çevirirken uç kutuların genişliği diğer kutuların yalnızca yarısıdır
      • Bu da algoritmanın uç değerleri üretmesini "daha zor" hale getirir
      • Tekdüze [0,1] gürültüsü üretip standart formülle yuvarlarsanız 0 ve 255 değerleri, diğer tamsayılara göre yarı sıklıkta oluşur
    • Bir milyon tekdüze rastgele sayının histogramında 0 ve 255 sütunlarının diğerlerinin yarı yüksekliğinde olduğu görülebilir
    • Yine de uç değerlerden kaçınma yanlılığının pratikte sorun olduğu bir durum düşünmek zordur
      • Orijinal görüntü yine kayıpsız biçimde ileri-geri dönüştürülebilir (uint8 → float → uint8)
      • 0.0 veya 1.0’ın biraz dışına çıkan sonuçlar da doğru kutuya yuvarlanır, böylece çıktı dağılımı dengelenir
      • Örneğin işleme sırasında renkten 0.005 çıkarılırsa standart yöntemde siyah 0’ın altına iner, alternatif yöntemde pozitif kalır; ancak iki yöntemde de sonuçta tamsayı 0 üretilir
  • Kesin olmama

    • Standart yöntemde kayan noktalı değerler tam değildir; örneğin 128/255.0 ≈ 0.501961 iken 128/256.0 = 0.5
    • Yuvarlama hatası nedeniyle kayan noktalı değerler arasındaki mesafe çok küçük ölçüde değişir, ancak hata son derece küçüktür ve pratikte sorun yaratmaz
      • 32 bit kayan nokta 23 bit mantisaya sahiptir ve hata en düşük anlamlı bit düzeyindedir; 2⁻²³’ten küçüktür
      • %0.00001 düzeyindeki göreli hata, hassas görüntü işlemede bile anlamsızdır; bu kesin olmama teknik değil, estetik bir meseledir
  • Tamsayı aralıklarına denk düşmeyen değerler

    • Alternatif yöntem, her kayan noktalı değeri iki tamsayının tam ortasına yerleştirir
      • Asıl niceleme değeri bilinmediğinden, art arda gelen iki tamsayının orta noktası iyi bir tahmin olarak görülebilir
    • Bunun dithering için daha elverişli olduğu da öne sürülür (Andrew Kesler’ın 2015 tarihli blog yazısı "Converting Color Depth")
      • Sınır durumlarıyla uğraşmadan gürültü eklenebilir
      • Buna karşılık standart formüldeki tuhaf uç değerler, gürültü dağılımının tutarlı kalması için daha dikkatli işlem gerektirir

İki tür niceleyici

  • Bu iki yaklaşım, tekdüze skaler niceleyici (uniform scalar quantizer) türlerinden ikisi olarak görülebilir
  • Wikipedia niceleme maddesine göre işaretli giriş verileri için tekdüze niceleyiciler iki türe ayrılır
    • mid-tread: 0’ı, yeniden oluşturulan 0 değer seviyesine eşler (basamağın düz kısmı)
    • mid-riser: 0’ı, 0 değerinin sınıflandırma eşiğine eşler (basamağın dik yüzü)
    • Wikipedia kaynak olarak Allen Gresho’nun 1977 tarihli "Quantization" makalesini gösterir
  • Niceleyici formülleri (L çıktı seviyesi sayısıdır; örneğin 256)
    • mid-tread basamak niceleyici: kodlama k = trunc(xL + 0.5), çözme yₖ = k/L
    • mid-riser basamak niceleyici: kodlama k = trunc(xL), çözme yₖ = (k+0.5)/L
  • Bu iki yaklaşıma uygulandığında
    • Standart formül = mid-tread (L=255)
    • Alternatif formül = mid-riser (L=256)
  • Standart yöntem, işaretsiz girdide mid-tread kullanırken L=255 kodunu seçen bir kombinasyondur; 8 bit giriş için optimal değildir
    • Bunun nedeni 0.0 ve 1.0 uç noktalarını doğrudan eşlemenin programlama açısından pratik olmasıdır
  • Daha yüksek niceleme hatası, ama pratikte değil

    • Eğer sisteminiz tekdüze dağılmış x∈\[0,1\] gerçek sayıları 8 bit tamsayıya kodlayıp tekrar gerçeğe dönüştürüyor olsaydı, standart formül bant genişliği israfı olurdu
      • Standart yöntemin temsil aralığı [-0.5/255, 255.5/255] olduğundan, [0,1] girdisi için gerekenden geniştir ve yeniden oluşturma hatasını artırır
      • StackOverflow kullanıcısı Peter Mudrievskij’in hesabına göre ortalama mutlak hata 255 böleni için 1/1020, 256 böleni için 1/1024 olur; yani teoride 256’ya bölmek biraz daha hassastır
    • Ancak pratikte yapılan şey bu değildir
      • Varsayım, 8 bit RGB görüntüyü yükleyip işledikten sonra tekrar kaydetmektir; kaydederken niceleme yöntemini kontrol edemeyebilirsiniz ve kaybolan bilgi kalıcı olarak yok olur
      • Görüntü standart formülle çarpılıp yuvarlanarak kaydedildiyse, yüklerken 256’ya bölmek bu hassasiyeti geri getirmez
      • Daha düşük yeniden oluşturma hatası argümanı yalnızca kaydetme ve yüklemeyi birlikte kontrol ettiğinizde anlamlıdır
    • Başkasının görüntüsünü alternatif formülle yüklemek ise daha fazla hata üretebilir
      • Çoğu görüntü muhtemelen standart formülle nicelemendiği için yanlış ölçekle çözmek teorik olarak daha hatalıdır
      • Pratikte ise renkler mutlak ölçümler olmadığından, bu durum yalnızca biraz daha dar aralıkta küçük bir ofsetle işlem yapmak anlamına gelir
    • Bu iki niceleyicinin kodlama ve çözme adımları karıştırılmamalıdır; aksi halde kolayca bozuk kod ortaya çıkar

Sonuç

  • Tanımadığınız birinden gelen bir görüntüyü işleyecekseniz RGB değerlerini 255 ile normalize etmelisiniz
    • Kayan noktalı değerlerin tam olmaması ya da soyut yeniden oluşturma hatası kaygıları, alternatifi seçmek için iyi nedenler değildir
  • Görüntünün hem kaydını hem yüklenmesini tamamen kontrol ediyor, 0’ı 0’a eşlemeniz gerekmiyor ve işleme kodunun 8 bit dinamik aralığa bağlı olmasını sorun etmiyorsanız 256’ya bölerek çok az daha yüksek hassasiyet elde edebilirsiniz
    • Ancak bir ekip arkadaşının görüntüyü standart formülle yükleyip planı bozabileceğini unutmayın

Diğer görüşler

2 yorum

 
GN⁺ 2026-06-03
Hacker News yorumları
  • Renk değerinin tam olarak ne anlama geldiği, bileşen başına 8 bit kullanımında çoğu zaman pek mesele olmaz. Paydanın 255 mi 256 mı olmasıyla oluşan hata çok küçüktür; farkı görebilmek için hem renk algınızın iyi olması hem de ekrana çok yaklaşmanız gerekir, ayrıca monitörler ve telefon ekranları da genelde kalibre edilmemiştir
    Ama mikrodenetleyiciyle VGA sinyali üretip renk çıkış pinleriniz sadece 8 adetse (kırmızı 3, yeşil 3, mavi 2), iş epey can sıkıcı hale gelir. Bu durumda renk değeri, VGA monitörüne gönderilmesi gereken 0V~0.7V gerilim seviyesinin ta kendisidir
    Mavi kanal 0→0V, 1→0.23V, 2→0.47V, 3→0.7V olarak eşlenir; kırmızı/yeşil ise 0→0V, 1→0.1V, …, 7→0.7V olur. Uç noktalar dışında mavi gerilimleri kırmızı/yeşil gerilimlerle hiç çakışmadığı için saf gri görmek mümkün olmaz; en yakın renk bile farkın yönüne göre hafif mavi ya da sarımsı görünür
    Dahası, maviyi diğer kanallarla karıştıran neredeyse tüm gradyanlar da kaymış görünür. Örneğin saf kırmızıdan saf beyaza giden çizgi üzerindeki en yakın renkler biraz turuncu ya da morumsu görünebilir
    Raspberry Pi Pico 2 üzerinde çift tamponlu 320x240 framebuffer ile 8 bit renkli VGA çıkışı üreten kod burada: https://github.com/moefh/pico-vga-8bit-demo

    • Çocukken parazitli CRT ekrana bakarken kenarlarda beliren soluk mavi ve sarı çizgileri hatırlıyorum. Neden özellikle bu iki renk olduğunu hep merak etmiştim; sebep aynıysa, demek ki cevabı ancak şimdi öğrenmiş oldum
    • Gama düzeltmesi atlanmış. PC, değeri 0~255 aralığından gerilime çevirmeden önce genelde onu 2.2 kuvvetine yükseltir
      Bu durumda küçük ve büyük değerler arasındaki fark çok daha belirgin hale gelir: 2^2.2 = 4.595, 255^2.2 = 196,964.699
    • Bu problem için en iyi yaklaşım zamansal dithering gibi görünüyor. Piksel başına delta-sigma modülasyonu yapmak oldukça kolay olabilir
      Eğer 30Hz'de değişiyorsa, insanların hafif mavimsi ile hafif sarımsı tonlar arasındaki farkı ayırt etmesi zor olur gibi geliyor
    • Demek ki 80'lerde RGBI renkleri bu kadar yaygındı
  • 255 lehine bir argüman olarak, siyah-beyaz görüntü gibi uç bir örneğe bakabilirsiniz. Tek bitte 0 siyahtır, 1 beyazdır
    0'ın 0.0'a, 1'in de 1.0'a eşlenmesi gerektiği oldukça açıktır. Sonuçta bu siyah-beyazdır; açık gri (0.25) ve koyu gri (0.75) değildir. Yani siyah-beyaz görüntü 2'ye değil 1'e göre normalize edilir
    2 bit olsaydı genelde 0=siyah, 1=açık gri, 2=koyu gri, 3=beyaz olurdu; dolayısıyla bunu 0.0, 0.33, 0.66, 1.0'a eşlemek doğaldır. Siyah siyah, beyaz beyaz kalmalı ve aralıklar da eşit olmalıdır; bu yüzden 3'e göre normalize edilir
    Bu mantığı 8 bite kadar sürdürünce 255'e göre normalizasyon elde edilir. 8 bitte fark çok küçük olsa bile siyahın 0.0, beyazın 1.0 olması gerekir
    8 bitte 256'ya göre normalize etmek gibi alternatif yaklaşımda ise çıkış aralığı bit sayısına göre değişir. 1 bit için [0.25, 0.75], 2 bit için [0.125, 0.875] gibi olur. Genelde istenen şey, bit sayısı arttıkça ton nüanslarının artmasıdır; kontrastın değişmesi değil

  • Gerçekten düşündürücü bir yazıydı; kişisel olarak benimsediğim bazı varsayımları yeniden sorgulamama neden oldu
    Elektrik mühendisliği perspektifinden bakınca, yazıdaki “iki tür niceleyici” sunumuna katılmak zor. Matematiksel olarak titiz olabilir ama gerçek sistemleri temel alan bir açıklama değil
    ADC'lerde doğası gereği her zaman ±1/2 LSB niceleme belirsizliği vardır. Aktarım karakteristiği her zaman mid-tread örneklemedir; en azından ben aksini gösteren bir örnek görmedim. Bu, bipolar ADC için de unipolar ADC için de geçerlidir
    En düşük kod negatif referans gerilimine, en yüksek kod ise pozitif referans gerilimine karşılık gelir. Aktarım karakteristiği grafiği, yazıda gösterildiği gibi en üst ve en alt aralıkların fiilen 1/2 LSB genişliğinde olduğunu gösterir
    Unipolar sistemlerde ara gerilimler tam olarak temsil edilemez; başka bir deyişle gri problemi ortaya çıkar. Bipolar sistemlerde 0V, mid-tread'in N/2 değerine denk gelir ama bu, “256 aralık” olduğu anlamına gelmez
    Bu yüzden ben yine de (VREF+ - VREF-) * k / (2^N - 1) kullanırım. Yani 255 normalizasyonuna katılıyorum. Sonuçta bu bir çit direği hatası gibi: değer sayısı N ama aralık sayısı N-1. Değerlerden daha az aralık varsa, bir aralığı iki değer arasında paylaşmak gerekir; bu yüzden uçlarda 1/2 LSB'lik aralık oluşur

    • Gördüğüm tüm ADC belgeleri pozitif tam ölçeğin temsil edilemediğini söyler. Örneğin 8 bit ±1V ADC'de -128, -1V anlamına gelir; +127 ise 127/128=0.99219V anlamındadır
      126'dan 127'ye geçiş, pozitif tam ölçeğin 1.5 LSB altında gerçekleşir. 1 LSB farkı 2/255=0.00784V değil, 1/128=0.00781V fark anlamına gelir
      Ama pratikte gerilim ve belirsizlik önemliyse, bu farkların çoğu zaman pek önemi yoktur. Referans geriliminde bias vardır ve doğrusal olmama hataları da bulunur. 1 LSB ne tam olarak 1/128'e ne de 2/255'e denk gelir; kalibrasyon için ek parametreler gerekir
  • Bu, bilimsel hesaplamada sözü edilen düğüm merkezli örnekleme ile hücre merkezli örnekleme farkının 1 boyutlu bir versiyonu gibi. Değerin aralığın ortasında mı (ya da üçgen/tetrahedron merkezinde mi), yoksa aralık sınırında mı (ya da üçgen/tetrahedron köşesinde mi) bulunduğuna karar vermek gerekir
    Bilimsel hesaplamada, değerleri nasıl yorumlamak gerektiğini bilmeden veri işlemeye başlamak anlamsızdır. Ses sinyali işlemede de, elinizde sadece bir tamsayı akışı varsa, orijinal sinyal üzerinde hesap yapabilmek için bu tamsayıların hangi temsil niyetiyle verildiğini — örneğin mu-law kodlaması mı yoksa lineer mi olduğunu — bilmeniz gerekir. Buna dair cevabı, değere eşlik eden metadata'nın vermesi beklenir
    Ama 8 bit piksel değerlerinde, temsil niyetini aktaracak düzgün bir dosya formatı metadata'sı yoksa ortada kalırsınız ve tek bir doğru cevap da olmaz. Yazarın dediği gibi kendi kullanımında daha iyi sonuç veren yaklaşımı seçti diye onu eleştirmek doğru olmaz; ama bağlamdan kopuk bitlerin anlamı bozduğunu söylemek mümkündür

    • ESA'nın Sentinel-2 level-2 uydu görüntüsü nicelemesinde kullanılan normalizasyon değeri aklıma geldi
      Yaklaşık olarak şöyle: Digital Number DN=0, “NO_DATA” değeri olarak ayrılır; DN [1; 1;215-1] aralığındayken L2A SR yansıtırlık değeri L2A_SRi = (L2A_DNi + BOA_ADD_OFFSETi) / QUANTIFICATION_VALUE olur
      https://sentiwiki.copernicus.eu/web/s2-products
  • Burada 0'dan 255'e kadar 256 seviye olduğunu varsayan bir hata var. Aslında 8 bit ile ifade edilebilen 256 değer vardır ve 0 (siyah) ile 255 (saf beyaz) arasında 255 aralık bulunur
    Bu yüzden 255'e bölmek sorun değildir. Elbette 128 tam olarak orta gri değildir ve 0~255 aralığındaki nicemlenmiş 8 bit değerler neredeyse her zaman doğrusal algısal uzayda değil sRGB'dedir
    Modern API'lerde örnekleme konumları ele alınırken de benzer bir karışıklık ortaya çıkar. Çünkü konumlar piksel merkezi olarak değil koordinat olarak belirtilir

    • BeOS API, piksel merkezi temellidir. Artık kimse umursamıyor olabilir ama
  • Cebirsel olarak bakıldığında cevap açıkça f(x) -> [0, 255]'tir
    f(n * 0) == n * f(0) sağlanmıyorsa tuhaf şeyler olur. Örneğin f(x) -> [0, 255] ise f(0) + f(0) + f(0) = 0 + 0 + 0 = 0 = f(0) olur
    Buna karşılık f(x) -> [0.5/8, 7.5/8] ise f(0) + f(0) + f(0) = 0.5/8 + 0.5/8 + 0.5/8 = 1.5/8 != f(0) olur
    İkincisini seçerseniz, x tarafında yapılan bir hesapla f(x) tarafında yapılan bir hesabın birbiriyle tutarlı olmasını bekleyemezsiniz. Yani cebirsel karşılık bozulur

  • +0.5 çözümünü desteklemek istiyorum. Birincisi, kenarlardaki yarım boyutlu aralıkları sevmiyorum; ikincisi, 255 tabanlı gösterim genelde HDR değil, SDR görüntü içindir
    RGB değerleri, belirli bir adaptasyon durumuna göre parlaklığı temsil eder; gündüz sahnesindeki “0”, “parlaklık 0” değildir. Yalnızca en parlak noktanın yaklaşık 0.001 katıdır ve foton sayısı yüz binlerce, hatta milyonlarca olduğu için 0'dan çok büyüktür
    Bir bakıma göz, kontrastı kayan bir ölçek üzerinde deneyimler ve sistem içinde mutlak bir 0 yoktur. Örneğin yayın sistemleri tarihsel olarak SDR parlaklık aralığı için 16~235 kullandı. “Mutlaka 0 olmalı” mantığının yanlılık ürettiğini düşünüyorum ve çoğu durumda 0'a gerek olmadığını savunuyorum

    • VFX için çok fazla görüntü işleme ve render yapmış biri olarak, bunun ardından renk uzayı dönüşümü geldiğinin unutulduğunu düşünüyorum. Eski SDR'de sRGB'nin doğrusal Rec.709'una, daha yeni biçimlerde ise daha geniş bir renk gamına dönüşüm yapılıyor. Bu nedenle dinamik aralığın sıkışması yüklemeden sonra gerçekleşir
      Ayrıca görüntü işleme ve compositing iş akışlarının önemli bir kısmı, doğru ya da yanlış, 0'ın 0 anlamına geldiğini varsayar. Bu yüzden 8 bit'te 0u'nun 0.0f'ye, 255'in de 1.0f'ye eşlendiği kabul edilir. Maske ya da alfa değerinde 0 değeri 0.0'ı az da olsa aşarsa, bir yerlerdeki kod 0.0 sabit eşiğiyle başka işlemleri maskeleyip artefaktlar üretir. Tersine, alfada 255 artık 1.0f değilse, premultiply sonrasında nesne çok hafif şeffaflaşır
      Aynı şey, +0.5 yüzünden maskelemede 254'ün 1.0f olması durumunda da yaşanabilir
    • Yazı RGB'ye odaklanıyor ama aynı nicemleme sorunu, ayrık gösterim ile sürekli gösterim arasında eşlenen her tür sinyalde vardır
      Kilit nokta 0 fotonu temsil edip etmemek değil, 1 bayta sığan bilgiyi en üst düzeye çıkarmaktır. İdeal olarak bayt değeri 0 daha az kullanılmamalı ve 0. kovaya düşmesi gereken verilere bias eklenmemelidir. Parlak ile çok parlak arasında giden bir renk uzayı olsa bile, tüm baytlar parlaklık aralığının eşit büyüklükte parçalarını temsil etmelidir
    • Yayın sistemlerinin tarihsel olarak SDR parlaklık aralığı için 16~235 kullanmış olması zaten sorunun bir parçası. Ne yazık ki “modern” HDMI bile hâlâ bu tuhaf uygulamadan mustarip; ekran ile kaynak anlaşmazsa görüntü soluk görünür ya da siyahlar ezilir
    • Her iki çözüm de 0.5 ekler. Fark, bunun sürecin hangi noktasında yapıldığıdır
    • İlginç bir fikir ama sanki dünya yerinden oynuyormuş gibi hissettiriyor. İşleme programı açısından bakınca, eski siyah (0.0) ve beyaz (1.0) artık çok koyu gri ve çok açık griye dönüşüyor
  • Cetvel 12 inçe kadar gidiyorsa, üzerindeki nokta sayısı olan 13'e değil, uzunluk L'ye göre normalize etmelisiniz

    • Bu benzetme kafamı karıştırdı. “Cetvel” 0~255 diye işaretlenmiş 256 noktaya sahip 255 inçlik bir cetvel mi, yoksa 1 inçlik 256 aralığı olan 256 inçlik bir cetvel mi, yani L = 256×1 mi, emin değilim
    • Aslında saymaya çalıştığınız şey çit direkleriyse çit direği hatası hata değildir
    • Doğru, ama >> 8 çok daha hızlı
    • Sayıların noktaları temsil ettiğine kim karar verdi? Noktalar arasındaki aralıkları temsil ediyor da olabilirler
    • Yoksa ben mi aptalım? 0 başlangıç noktasından başlamaz mı?
  • Uzun zamandır düşünmediğim bir konuyu ele aldığı için okuması keyifli bir yazıydı. Oyun geliştirmede oyun mantığı kayan noktalı matematik kullanırken, pixel art'ı tamsayı koordinatlarına çizmek zorunda kaldığımız anları hatırlattı
    Birkaç yerde +0.5'e benzer yöntemler kullanarak işleri daha az tuhaf göstermeye çalışmıştım. Özellikle hareketli kamera varken böyleydi; kamerayı da kırpmak gerekiyordu
    Aşağıda bağlantısı verilen Jonathan Blow'un 2002 tarihli yazısı [1] da ilginçti. İlk yazıdaki görselleştirme, konuya daha derin indikçe çok yardımcı oluyor
    [1] https://web.archive.org/web/20240706043551/https://number-no...

 
GN⁺ 2026-06-02
Lobste.rs görüşleri
  • Dağınık görünüyor ama doğru; değer 255 olmalı
    Sezgisel gelmiyorsa bunu 2 bitlik dejenere bir örnek üzerinden düşünebilirsiniz. Olası tamsayı değerleri yalnızca 0, 1, 2, 3 olduğunda tamsayı→kayan nokta dönüşümünü tamamen hesaplarsanız, siyah/beyazın gerçekten siyah/beyaz olmaması ya da aralıkların bariz biçimde eşit dağılmaması gibi tuhaf davranışlardan kaçınmak için sonuç 0.0, 0.33..., 0.66..., 1.0 olur
    Dolayısıyla ters dönüşüm de 4(2^2) ile değil, 3 ile çarpma şeklinde olur
    • İlk kısmı doğru, ama buradan “o hâlde ters dönüşümde 4 değil 3 ile çarpmalısın” sonucu çıkmaz
      Ters dönüşümde kuantalama (yuvarlama) gerekir ve simetriyi bozan kritik nokta tam da budur
      0..=1 aralığında eşit bir gerçek sayı gradyanı oluşturup bunu 0, 1, 2, 3'e kuantalarsanız, 3 ile çarpmanın eşit sonuç vermediğini görürsünüz. ×3 sonrası round() 1 ve 2'yi aşırı temsil eder; ×3 sonrası floor ya da ceil ise 0 veya 3'ü tekillik gibi içeri katlayarak gradyanın 4 renkten yalnızca 3'ünü kullanıyormuş gibi görünmesine yol açar
      /3 ve ×3 mantığı, tam sayıları gidiş-dönüş çevirmek için kulağa doğru geliyor olabilir; ama ara değerler yuvarlama seçimine büyük ölçüde bağlıdır ve veri işlemeye başladığınız anda bu önemli hâle gelir
      Tamsayı oranlarının eşit olması ancak (4-ε) ile çarpıp aşağı yuvarladığınızda gerçekleşir; bu da ×4, floor(), clamp() ile aynıdır. Garip bir 1 farkı ya da ε farkı hatası gibi hissettirse de sezgisel olarak en iyi görünen çözüm budur
  • Başlık yüzünden çok kafam karıştı. Kasıtlı mı bilmiyorum ama sonuçta soru “0..1, [0..255.0] aralığına mı karşılık geliyor, yoksa [0.5..255.5] aralığına mı?” gibi görünüyor
    Benim için cevap her zaman “elbette” [0.0..255.0] olmuştu, ama görünüşe göre bu herkes için o kadar da bariz değil
    Yazıda “uç” aralıkların diğer aralıkların yalnızca yarısı kadar kapasiteye sahip olduğu söyleniyor; bence bu çerçeveleme de doğru değil
    Eğer [0..1] dışında değer yoksa, bunun daha dar bir aralık gibi görünmesi render etmenin bir yan ürünü. Kovaları, aralığın dışında değer olmadığını bilerek kestiğiniz için sadece daha dar render ediliyor
    Tersine, eğer [0..1] dışında değerler varsa bu aralık sonsuzdur. Yazı ikincisini kabul ediyor ama birincisini etmiyor
    Birincisini kabul ettiğiniz anda doğru davranış oldukça açık görünüyor; ama böyle bir yazının ortaya çıkmış olması bile bunun nesnel olarak o kadar “açık” bir mesele olmadığını gösteriyor :D
    • Eğer gerçekten 0…255.0'ın apaçık doğru olduğunu düşünüyorsanız, hangi kayan nokta değer aralığı tamsayı 0'a dönmeli ve hangi aralık tamsayı 255'e dönmeli?
      0..<1 tamsayı 0'a gidiyor, 254>..255.0 da tamsayı 255'e gidiyor derseniz 128 arada kaybolur. Muhtemelen 127.5..128.5 aralığının 128'e gitmesini istersiniz; peki o zaman bu yarımlar nereye gitmeli?
      128'i doğru yere koymak için tüm aralığı biraz kaydırırsanız, 0..0.99609375 tamsayı 0'a eşlenmiş olur
  • Standart yaklaşım da sanki insanların doğal olarak round() çağırmasından doğmuş gibi görünüyor
    İnsanlara bu yöntem oldukça doğal geldiği için, sadeliği yüzünden standart hâline gelmiş gibi
  • 256 ile elde edilmeye çalışılan şeyin ters yaklaşımının da işe yarayıp yaramayacağını merak ediyorum. Yani 0.0'ı 0'a, 1.0'ı 255'e gönderip diğer kayan nokta değerlerini 1 ile 254 arasına eşlemek
    uint8_t output = 0.0f >= result  
                     ? 0  
                     : 1.0f <= result  
                     ? 255  
                     : 1 + 253*result;  
    
    İşleme sırasında da siyahın siyah, beyazın beyaz olarak kalması güzel olurdu
    • Bunu yaparsanız 0 ve 255, birim aralıkta diğer sayılardan daha büyük bir pay alır. Yaklaşık %0,8, yani 255/253 kadar
  • İlk görsel bende bozuk görünüyor
    • Yazının yazarı burada. Görsel dosyasının bozuk olduğunu mu kastediyorsunuz? pngcrush ile sıkıştırmıştım. Yoksa görsel içeriğinde bir sorun mu olduğunu söylüyorsunuz?