iOS 圖片抖動(dòng)算法

弗洛伊德-斯坦伯格抖動(dòng)算法

這是一個(gè)真實(shí)的魔法技術(shù)。它愚弄了你的眼睛和大腦,讓你以為自己看到的顏色要比實(shí)際的多。
image.png
一般來(lái)說(shuō),抖動(dòng)是通過(guò)增加人工噪聲去減少一個(gè)圖像的顏色空間,主旨在于,一個(gè)區(qū)域的光量應(yīng)該保持一致。
image.png
弗洛伊德-斯坦伯格抖動(dòng)算法對(duì)周?chē)南袼厥褂梅蔷鶆蚍植嫉牧炕`差達(dá)到抖動(dòng)的目的。這就意味著要先將中心像素四舍五入為0或1,而后將殘差加入其周?chē)南袼刂小?/h5>
image.png
以上你看到的三張圖片都是灰階抖動(dòng)的,它們?nèi)慷际侵挥蓛煞N顏色的噪音組成,而其余的信息,當(dāng)然是因?yàn)槟愕拇竽X在轉(zhuǎn)嘍。

算法實(shí)現(xiàn)

#pragma mark - 分配內(nèi)存
 uint32_t* oldImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight);
 uint32_t* newImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight);
#pragma mark - 創(chuàng)建context
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();// 色彩范圍的容器
CGContextRef oldContext = CGBitmapContextCreate(oldImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
CGContextDrawImage(oldContext, CGRectMake(0, 0, imageWidth, imageHeight), self.CGImage);
CGContextRef newContext = CGBitmapContextCreate(newImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
CGContextDrawImage(newContext, CGRectMake(0, 0, imageWidth, imageHeight), self.CGImage);
#pragma mark -遍歷像素計(jì)算殘差
 //殘差
                    int eRgb[3];
                    if (nearColor == 0) {
                        newptr[3] = 0;
                        newptr[2] = 0;
                        newptr[1] = 0;
                        newptr[0] = 255;
                        eRgb[0] = r;
                        eRgb[1] = g;
                        eRgb[2] = b;
                    } else {
                        newptr[3] = 255;
                        newptr[2] = 255;
                        newptr[1] = 255;
                        newptr[0] = 255;
                        eRgb[0] = r-255;
                        eRgb[1] = g-255;
                        eRgb[2] = b-255;
                    }
                    //殘差 16分之 7、5、3、1
                    float rate1 = 0.4375;
                    float rate2 = 0.3125;
                    float rate3 = 0.1875;
                    float rate4 = 0.0625;
                    uint32_t rgb1 = [self getPixel:oldImageBuf width:imageWidth height:imageHeight row:row column:column+1 rate:rate1 eRgb:eRgb];
                    uint32_t rgb2 = [self getPixel:oldImageBuf width:imageWidth height:imageHeight row:row+1 column:column rate:rate2 eRgb:eRgb];
                    uint32_t rgb3 = [self getPixel:oldImageBuf width:imageWidth height:imageHeight row:row+1 column:column-1 rate:rate3 eRgb:eRgb];
                    uint32_t rgb4 = [self getPixel:oldImageBuf width:imageWidth height:imageHeight row:row+1 column:column+1 rate:rate4 eRgb:eRgb];
                    [self setPixel:oldImageBuf width:imageWidth height:imageHeight row:row column:column+1 value:rgb1];
                    [self setPixel:oldImageBuf width:imageWidth height:imageHeight row:row+1 column:column value:rgb2];
                    [self setPixel:oldImageBuf width:imageWidth height:imageHeight row:row+1 column:column-1 value:rgb3];
                    [self setPixel:oldImageBuf width:imageWidth height:imageHeight row:row+1 column:column+1 value:rgb4];
#pragma mark - 獲取像素
- (uint32_t)getPixel:(uint32_t*)imageBuf width:(int)width height:(int)height   row:(int)row column:(int)column rate:(float)rate eRgb:(int *)eRgb {
    if (row < 0 || row >= height || column < 0 || column >= width) {
        return 0xFFFFFFFF;
    }
    int index = row * width + column;
    uint32_t *ptr = imageBuf + index;
    uint8_t* newptr = (uint8_t*)ptr;
    uint8_t r = newptr[3];
    uint8_t g = newptr[2];
    uint8_t b = newptr[1];
    uint8_t a = newptr[0];
    int er = eRgb[0];
    int eg = eRgb[1];
    int eb = eRgb[2];
    r = clamp(r + (int)(rate*er));
    g = clamp(g + (int)(rate*eg));
    b = clamp(b + (int)(rate*eb));
    return (r << 24) + (g << 16) + (b << 8) + a;
}

#pragma mark - 設(shè)置像素
- (void)setPixel:(uint32_t*)imageBuf width:(int)width height:(int)height   row:(int)row column:(int)column value:(uint32_t)value {
    if (row < 0 || row >= height || column < 0 || column >= width) {
        return;
    }
    int index = row * width + column;
    uint32_t *ptr = imageBuf + index;
    uint8_t* newptr = (uint8_t*)ptr;
    int r = (value & 0xFF000000) >> 24;
    int g = (value & 0x00FF0000) >> 16;
    int b = (value & 0x0000FF00) >> 8;
    int a = value & 0x000000FF;

    newptr[3] = r;
    newptr[2] = g;
    newptr[1] = b;
    newptr[0] = a;
}

總結(jié)

圖片抖動(dòng)算法就是獲取當(dāng)前點(diǎn)的像素與相鄰的點(diǎn)的像素比較,并進(jìn)行相應(yīng)處理的過(guò)程,是一個(gè)區(qū)域的光量保持一致

代碼傳送門(mén)

請(qǐng)關(guān)注我的專(zhuān)題 iOS - Developer - OC 進(jìn)階大全

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 那些想獲得精神分析知識(shí)的人們所面臨的困難很多,尤其是缺乏一本適用的教科書(shū)可用以開(kāi)始他們的研究。這些人從前可在三類(lèi)課...
    暖陽(yáng)_1332閱讀 1,309評(píng)論 0 1
  • 正確寫(xiě)法應(yīng)該是:弗洛伊德 弗洛伊德生平 作為一個(gè)治療精神疾病的醫(yī)生,弗洛伊德創(chuàng)立了一個(gè)涉及人類(lèi)心理結(jié)構(gòu)和功能的學(xué)說(shuō)...
    昭的私房家伙閱讀 619評(píng)論 0 0
  • 一直到要放寒假,嚴(yán)安也沒(méi)有來(lái)找過(guò)蘇瑾芮。兩個(gè)人即使在路上碰到,也會(huì)裝作不認(rèn)識(shí),匆匆走過(guò)。蘇瑾芮在心里偷偷松了口氣,...
    趙小作z閱讀 525評(píng)論 0 43
  • Objective-c 線(xiàn)程系列一 atomic是安全的嗎Objective-c 線(xiàn)程系列二 @synchro...
    海森V閱讀 469評(píng)論 0 0
  • 想要寫(xiě)點(diǎn)東西很久了,嗯,卻只是想。深夜不是工作,不是考慮寫(xiě)什么,只是單純的玩的太晚了??粗粗?,總要開(kāi)始,這便是開(kāi)...
    南瓜芝士呢閱讀 427評(píng)論 0 0

友情鏈接更多精彩內(nèi)容