1. 程式人生 > >自己編碼使用去色、曲線、色階演算法實現照片懷舊特效

自己編碼使用去色、曲線、色階演算法實現照片懷舊特效

天下文章一大抄,看你會抄不會抄,這個演算法的初步雛形其實很簡單,很多傻瓜級的軟體業提供了相應的一鍵功能,比如美圖秀秀。其實這就是個簡單的調色功能,實現的方式五花八門,沒有一個固定的標準,我們下面僅以幾個開源的軟體中的演算法為例來說明實現過程。

      第一的參考演算法是來自Paint.net的,在專業的軟體中,這個功能的英文一般稱之為Sepia,在Paint.net中,這個演算法實現的主要程式碼如下:

this.desaturate =newUnaryPixelOps.Desaturate();this.levels =newUnaryPixelOps.Level(ColorBgra
.Black,ColorBgra.White,
newfloat[]{1.2f,1.0f,0.8f},ColorBgra.Black,ColorBgra.White);

      即先去色,然後再執行色階命令,似乎很簡單,而我們先看看效果。

        

        

                    原圖 Paint.net的效果 美圖懷舊特效的結果

從效果上比較接近的,這裡和美圖比較,並不是說美圖就是行業標準,只是做個參照而已,我這裡主要說說Paint.net這個程式碼的簡易實現(並不是照抄其程式碼,實際上我根本沒看Paint.net具體的實現程式碼,而只看其實現的思路)。

     第一步是個去色,去色的演算法有N多種,我們這裡以業界老大Adobe Photoshop提供的演算法為標準實現,主要C++程式碼如下:

void __stdcall Desaturate(unsignedchar*Src,intWidth,intHeight,intStride){int X,Y,Max,Min,Value;unsignedchar*Pointer;for(Y =0; Y <Height; Y++){Pointer=Src+ Y *Stride;for(X =0; X <Width; X++){if(*Pointer>=*(Pointer+1))
//取R/G/B各分量的最大和最小值的平均值{Max=*Pointer;Min=*(Pointer+1);}else{Max=*(Pointer+1);Min=*Pointer;}if(*(Pointer+2)>Max)Max=*(Pointer+2);elseif(*(Pointer+2)<Min)Min=*(Pointer+2);Value=(Max+Min)>>1;*Pointer++=Value;*Pointer++=Value;*Pointer++=Value;}}}

  可見PS的去色演算法的原理性實現還是很簡單的,就是取RGB通道最大值和最小值的平均值,這相當於在色相飽和度效果中的飽和度取0的效果。

     所謂色階指令,別看PS的Level介面做的很複雜,有N多輸入引數,其實內部也沒啥複雜的技術,簡單的講就是通過哪些引數計算出一個隱射表,最終都是通過Curve指令來實現的,下面先給出通過那些引數計算隱射表的過程:

voidGetLevelTable(unsignedchar*Table,unsignedcharInputLeftLimit,unsignedcharInputMiddle,unsignedcharInputRightLimit,unsignedcharOutputLeftLimit,unsignedcharOutputRightLimit){if(InputLeftLimit>253)InputLeftLimit=253;if(InputLeftLimit<0)InputLeftLimit=0;if(InputRightLimit>255)InputRightLimit=255;if(InputRightLimit<2)InputRightLimit=2;if(InputMiddle>254)InputMiddle=254;if(InputMiddle<1)InputMiddle=1;if(InputMiddle>InputRightLimit)InputMiddle=InputRightLimit-1;if(InputMiddle<InputLeftLimit)InputMiddle=InputLeftLimit+1;if(OutputLeftLimit<0)OutputLeftLimit=0;if(OutputLeftLimit>255)OutputLeftLimit=255;if(OutputRightLimit<0)OutputRightLimit=0;if(OutputRightLimit>255)OutputRightLimit=255;for(intIndex=0;Index<=255;Index++){doubleTemp=Index-InputLeftLimit;if(Temp<0){Temp=OutputLeftLimit;}elseif(Temp+InputLeftLimit>InputRightLimit){Temp=OutputRightLimit;}else{doubleGamma= log(0.5)/ log((double)(InputMiddle-InputLeftLimit)/(InputRightLimit-InputLeftLimit));Temp=OutputLeftLimit+(OutputRightLimit-OutputLeftLimit)* pow((Temp/(InputRightLimit-InputLeftLimit)),Gamma);}if(Temp>255)Temp=255;elseif(Temp<0)Temp=0;Table[Index]=Temp;}}

我們先貼下PS的Level介面:

      

我想稍微懂點英語的人對理解上面程式碼中的引數和這個介面中的那些位置的標籤對應應該都沒有問題,如果有,請回到初中課堂。 

     這裡重點關注下上圖中有提示文字“調整中間調輸入色階"一項,PS的這一欄的輸入範圍是9.9-0.01,而我上述程式碼中對應的範圍是1-254,唯一的區別我覺得就是量化等級變得少了,這裡的主要演算法我記得是模仿的Gimp的。

     有了上述過程,只要在進行一個隱射就OK了,這部分其實就是PS的曲線功能的結果,雖然你看曲線的介面那麼複雜,其實都是一些控制而已。

void __stdcall Curve(unsignedchar*Src,intWidth,intHeight,intStride,unsignedchar*TableB,unsignedchar*TableG,unsignedchar*TableR){int X,Y;intByteCount=Stride/Width;unsignedchar*Pointer;for(Y =0; Y <Height; Y++){Pointer=Src+ Y *Stride;for(X =0; X <Width; X++){*Pointer++=TableB[*Pointer];*Pointer++=TableG[*Pointer];*Pointer++=TableR[*Pointer];}}}

最後給出Level命令的程式碼:

void __stdcall Level(unsignedchar*Src,intWidth,intHeight,intStride,ChannelDestChannel,unsignedcharInputLeftLimit,unsignedcharInputMiddle,unsignedcharInputRightLimit,unsignedcharOutputLeftLimit,unsignedcharOutputRightLimit){unsignedchar*Table=(unsignedchar*) malloc (256*sizeof(unsignedchar));unsignedchar*LinearTable=(unsignedchar*) malloc (256*sizeof(unsignedchar));for(int X=0;X<256;X++)LinearTable[X]= X;GetLevelTable(Table,InputLeftLimit,InputMiddle,InputRightLimit,OutputLeftLimit,OutputRightLimit);if(DestChannel== RGB)Curve(Src,Width,Height,Stride,Table,Table,Table);elseif(DestChannel==Blue)Curve(Src,Width,Height,Stride,Table,LinearTable,LinearTable);elseif(DestChannel==Green)Curve(Src,Width,Height,Stride,LinearTable,Table,LinearTable);elseif(DestChannel==Red)Curve(Src,Width,Height,Stride,LinearTable,LinearTable,Table);
    free(Table);
    free(LinearTable);}

對應上述Paint.net的level指令,我們把我們的呼叫形式更給為:

Level(Dest,Width,Height,Stride,Channel.Blue,0,152,255,0,255);Level(Dest,Width,Height,Stride,Channel.Red,0,101,255,0,255);

就OK了,具體的呼叫即效果可見後面的附件。

相關推薦

自己編碼使用曲線演算法實現照片懷舊特效

天下文章一大抄,看你會抄不會抄,這個演算法的初步雛形其實很簡單,很多傻瓜級的軟體業提供了相應的一鍵功能,比如美圖秀秀。其實這就是個簡單的調色功能,實現的方式五花八門,沒有一個固定的標準,我們下面僅以幾個開源的軟體中的演算法為例來說明實現過程。       第一的參考演算法是來自Paint.net的,在專

用動畫的方式畫出任意的路徑(直線曲線折現)

pub length 資料 new object n) 整體 for duration 原文:用動畫的方式畫出任意的路徑(直線、曲線、折現) 版權聲明:本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。歡迎轉載

canvas arc() 方法繪製弧線曲線圓形

canvas arc() 方法 arc() 方法建立弧/曲線(用於建立圓或部分圓),更多可參考《HTML 5 Canvas 繪製圖形影象》 提示1:如需通過 arc() 來建立圓,請把起始角設定為 0,結束角設定為 2*Math.PI。 提示2:請使用 stroke()&nbs

Android利用canvas畫各種圖形(點直線橢圓文字矩形多邊形曲線圓角矩形)

DrawView.java public class DrawView extends View { public DrawView(Context context) { super(context); } @Override protected void onDraw(Canvas c

matlab畫圖設定(座標軸曲線顏色)

a=linspace(1,2,10) plot(a,'--pr','linewidth',1.5,'MarkerEdgeColor','r','MarkerFaceColor','m','MarkerSize',10) legend('a','Location','b

Android 利用canvas畫各種圖形(點直線橢圓文字矩形多邊形曲線圓角矩形)

1、首先說一下canvas類: Class Overview The Canvas class holds the “draw” calls. To draw something, you need 4 basic components: A Bitmap

基於LVD貝葉斯模型演算法實現的電商行業商品評論與情感分析案例

一、 專案需求 現在大家進行網購,在購物之前呢,肯定會看下相關商品的評論,看下好評和差評,然後再綜合衡量,最後才會決定是否購買相關的商品。對一個指定商品,生產商,賣家,買家認同該商品的哪些優點/不認同

三維空間兩條直線的最短距離最近點及C++演算法實現

未經許可請勿轉載 在雙目視覺立體空間重建中,會根據兩個相機中的物體影象座標,求取給定三維座標系的三維座標,而可以根據物體 影象座標、相機內參、給定座標系的相機外參,求取相機光軸線的方程,從而實現立體重建,內外參、直線方程請執行 搜尋學習,本文主要是解決在已知空間兩直線求最短

第一篇博客:一個雙球遊戲 以及個人介紹

面向 都是 ued 計算機專業 bean b- view 需要 第一次 一、雙色球小遊戲 雙色球類(6紅1藍): 1 package top.liaoyingpeng.bean; 2 3 import java.util.Arrays; 4 5 publi

iOS塗塗鴉效果Swift仿喜馬拉雅FM抽屜轉場動畫拖拽頭像標籤選擇器等原始碼

iOS精選原始碼 iOS優質部落格 WKWebView是蘋果在iOS 8之後推出的框架WebKit中的瀏覽器控制元件, 其載入速度比UIWebView快了許多, 但記憶體佔用率卻下降很多, 也解決了載入網頁時的記憶體洩露問題. 現在的專

POI:單元格處理(對齊方式邊框填充合併)

public static void main(String[] args) throws Exception{         Workbook wb=new HSSFWorkbook(); // 定義一個新的工作簿         Sheet sheet=wb.crea

數組重,callapplybind之間的區別,this用法總結

步驟 -- 之間 undefined 定義 ply clas turn 需要 一、數組去重,直接寫到Array原型鏈上。 1 //該方法只能去除相同的數字 不會去判斷24和‘24‘是不同的 所有數字和字符串數字是相同是重復的 2 Array.prototype

Canvas入門(1):繪制矩形直線曲線等基本圖形

dsm etc win cti b2c 創建 例如 .com courier 來源:http://www.ido321.com/968.html 一、Canvas的基礎知識 Canvas是HTML 5中新增的元素,專門用於繪制圖形。canvas元素就相當於一塊“畫布

我們錯過了那麽多機會,怎麽辦(就是預見未來的能力,並且要投入,所以要主動學習儲備選擇,要不斷的思考)good

尋求 foruok red 檢索 自然 會有 zax 人生 rec 那天在IT職業咨詢QQ群裏聊天,提到騰訊、阿裏,我說跟著這兩家公司從小到大的朋友,都獲得了不菲的回報,成了富翁或者財務自由了。 有群友感嘆說:“是啊,我們錯過了那麽多機會。” 看

基於geohash6編碼實現相鄰4916網格合並

ceiling 分別是 代碼 char class ogr city 接下來 偏移 前面的兩篇文章介紹了geohash的基本原理及c#代碼相關實現,其中geohash 5位編碼單個網格覆蓋面積大約在24平方千米,6位編碼單網格覆蓋面大約在0.73平方千米, 相鄰編碼

js Math [ 隨機數絕對值四舍五入進一取整取整最大值最小值圓周率 ]

pre 最大 abs 取整 dom tran 絕對值 rip math <script> /* 數學對象:Math */ with (document) { write(‘<br>-3.5的絕

Mysql登陸退出更改環境編碼

root set alt word 小寫 大寫 http images com 登錄: mysql -h[數據庫地址] -u[username] -p[password] -P[端口]     //大寫P表示端口,小寫p表示密碼 例如:mysql -hlocalhost

開啟3個線程,這3個線程的ID分別為ABC,每個線程將自己的ID在屏幕上,要求輸出結果必須按ABC的順序顯示:ABCABC

abc multi adf ++ include vol form 主線程 tdi 1 #include <stdio.h> 2 #include <process.h> 3 #include <windows.h> 4 5

字符字符集編碼,以及它們python中會遇到的一些問題(下)

區別 做了 and 內部 eve nbsp nes 文字 相對 在看了很多的博客文章之後,總結整理得到了以下文章,非常感謝這些無私奉獻的博主! 文章末尾有本文引用的文章的鏈接,如果有漏掉的文章引用,可以發郵件聯系我,隨後再次附上鏈接! 侵刪!!! 這一部分是下篇,主要

編碼格式簡介:ASCII碼ANSIGBKGB2312GB18030和UnicodeUTF-8,BOM頭

family 用兩個 圖片 and 正是 全球化 asc 即使 little 編碼格式簡介:ASCII碼、ANSI、GBK、GB2312、GB18030和Unicode、UTF-8,BOM頭 二進制: 只有0和1。 十進制、十六進制、八進制: 計算機其實挺笨的,它只