專利名稱:具有用于重疊打印頭元件的補償?shù)膰娔蛴C的制作方法
技術領域:
本發(fā)明涉及噴墨打印領域,特別地公開了用于對具有重疊段的打印頭組件的隨時間變化的噴嘴失準進行補償?shù)姆椒ê脱b置。
共同未決專利申請 與本發(fā)明相關的各種方法、系統(tǒng)和裝置在申請人或受讓人與本發(fā)明同時提出的下列同類專利申請中揭示 PCT/AU00/00518,PCT/AU00/00519,PCT/AU00/00520, PCT/AU00/00521,PCT/AU00/00522,PCT/AU00/00523, PCT/AU00/00524,PCT/AU00/00525,PCT/AU00/00526, PCT/AU00/00527,PCT/AU00/00528,PCT/AU00/00529, PCT/AU00/00530,PCT/AU00/00531,PCT/AU00/00532, PCT/AU00/00533,PCT/AU00/00534,PCT/AU00/00535, PCT/AU00/00536,PCT/AU00/00537,PCT/AU00/00538, PCT/AU00/00539,PCT/AU00/00540,PCT/AU00/00541, PCT/AU00/00542,PCT/AU00/00543,PCT/AU00/00544, PCT/AU00/00545,PCT/AU00/00547,PCT/AU00/00546, PCT/AU00/00554,PCT/AU00/00556,PCT/AU00/00557, PCT/AU00/00558,PCT/AU00/00559,PCT/AU00/00560, PCT/AU00/00561,PCT/AU00/00562,PCT/AU00/00563, PCT/AU00/00564,PCT/AU00/00565,PCT/AU00/00566, PCT/AU00/00567,PCT/AU00/00568,PCT/AU00/00569, PCT/AU00/00570,PCT/AU00/00571,PCT/AU00/00572, PCT/AU00/00573,PCT/AU00/00574,PCT/AU00/00575, PCT/AU00/00576,PCT/AU00/00577,PCT/AU00/00578, PCT/AU00/00579,PCT/AU00/00581,PCT/AU00/00580, PCT/AU00/00582,PCT/AU00/00587,PCT/AU00/00588, PCT/AU00/00589,PCT/AU00/00583,PCT/AU00/00593, PCT/AU00/00590,PCT/AU00/00591,PCT/AU00/00592, PCT/AU00/00584,PCT/AU00/00585,PCT/AU00/00586, PCT/AU00/00594,PCT/AU00/00595,PCT/AU00/00596 PCT/AU00/00597,PCT/AU00/00598,PCT/AU00/00516, PCT/AU00/00517,PCT/AU00/00511,PCT/AU00/00501 PCT/AU00/00502,PCT/AU00/00503,PCT/AU00/00504 PCT/AU00/00505,PCT/AU00/00506,PCT/AU00/00507 PCT/AU00/00508,PCT/AU00/00509,PCT/AU00/00510, PCT/AU00/00512,PCT/AU00/00513,PCT/AU00/00514,和 PCT/AU00/00515, 這里通過交叉引用結合這些共同未決申請的公開。
背景技術:
在專利申請人的共同未決專利申請PCT/AU98/00550中提出了一系列噴墨打印裝置,用于通過采用新穎的噴墨機制,以高速跨頁寬進行打印。所揭示的裝置利用被作為整體結構的部分而建造的熱彎曲激勵器。
在這種裝置中,需要形成較大的噴墨噴嘴陣列以便在所需打印頭提供頁寬按需滴墨打印頭。期望地,要求對小墨滴尺寸的非常高的分辨率。例如,具有普通競爭力的打印系統(tǒng),如膠印允許到每英寸1600點(1600dpi)的分辨率。因此,作為例子,按上述分辨率打印,對于8英寸寬的A4頁打印頭,以此分辨率打印大約需要12800個噴墨噴嘴用于每種顏色。如采取標準的四色打印方法,這等于大約五萬一千個噴墨噴嘴。對于包括標準四色加上定色劑和IR墨的六色打印方法,這導致76800個噴墨噴嘴。不幸的是,從,如硅晶片基片的基片的連續(xù)段來制造大的單片打印頭是不實際的。
這主要是因為隨著結構尺寸的增大,產(chǎn)量會有相當?shù)臏p小。產(chǎn)出問題在半導體業(yè)中是一個已被詳細研究的問題,而噴墨設備的制造通常利用半導體或模擬半導體處理技術。特別地,該領域通常被公知為微電子機械系統(tǒng)(MEMS)。S Tom Picraux和Paul J McWhorter在1998年12月的IEEE Spectrum一篇題為“The Broad Sweep of Integrated MicroSystems”的文章中對MEMS領域進行了研究。
保持高產(chǎn)量的一種解決方案是制造分成若干段的很長的打印頭,并把這些段鄰接或重疊在一起。不幸的是,打印頭設備要求噴墨噴嘴非常高的間距,這就意味著,相鄰打印頭段之間的間隔必須被非常精確地控制,即使正常工作條件下存在熱循環(huán)。例如,為了提供1600點每英寸的分辨率,要求噴嘴到噴嘴的間隔為16微米左右。
打印頭的周圍環(huán)境和工作環(huán)境可在重疊區(qū)內產(chǎn)生打印頭的熱循環(huán),使相鄰打印頭段之間的重疊產(chǎn)生膨脹和收縮,其又導致在結果輸出圖像中產(chǎn)生假象。例如,在工作時,打印頭的溫度可比周圍環(huán)境升高25℃。打印頭組件還可是使用對打印頭段具有不同熱特性的材料制成的,導致組件之間不同的熱膨脹。硅基片可采用合成橡膠封裝,其熱膨脹系數(shù)分別是2.6×10-6和20×10-6每攝氏度。
假象的產(chǎn)生是由于打印頭表現(xiàn)二進制的連續(xù)色調圖像的有限的分辨率和人眼能檢測圖像中相鄰點的顏色上的0.5%的差異的能力。
發(fā)明內容
本發(fā)明的一個目的是提供一種機制來有效地、方便地補償重疊的打印頭段在工作期間的相對位移。
根據(jù)本發(fā)明的第一方面,本發(fā)明提供在包含多個重疊的打印頭段的噴墨打印頭中,其中,相鄰段之間的空間關系可隨時間變化,用于控制重疊段內的噴嘴噴射的方法,包括步驟(a)確定相鄰打印頭段之間的重疊量;(b)為在重疊段的重疊區(qū)域中的噴嘴產(chǎn)生一個半色調圖案;和(c)根據(jù)所述打印頭段的重疊區(qū)域內的所述量,調節(jié)所述半色調圖案,以減小由所述打印頭段的重疊而產(chǎn)生的假象。
優(yōu)選的是,確定重疊量的步驟采用對打印頭段的溫度的測量。所述半色調圖案優(yōu)選的是通過抖動矩陣或抖動容量產(chǎn)生,并且這種變換可以包括在利用抖動矩陣或抖動容量之前向當前連續(xù)色調像素輸出值增加重疊值??梢岳妹總€段上的基準帶(fiduciary strip)并使用干涉測量技術提供距離測量來代替溫度測量,以確定段之間的相對移動的程度。
根據(jù)本發(fā)明的又一方面,提供一種噴墨打印頭系統(tǒng),包括多個在空間上相互間隔開的重疊打印頭段;至少一種用于測量相鄰打印頭段之間的重疊度的裝置;為連續(xù)色調圖像提供半色調的裝置,以及用于調整相鄰打印頭段之間的重疊區(qū)域內的所述半色調裝置的裝置,以便減少所述相鄰段之間的假象。
所述調整半色調裝置的裝置可包括連續(xù)色調輸入、空間重疊輸入、以及二進制輸入,所述半色調裝置利用空間重疊輸入來改變連續(xù)色調輸入,從而產(chǎn)生用于抖動矩陣或抖動容量的查詢表中的各種各樣的連續(xù)色調輸入,以便產(chǎn)生輸出二進制值,從而調整打印頭段的重疊區(qū)域。用于調整半色調或抖動矩陣的裝置可以在硬件中實現(xiàn)或通過使用算法的軟件實現(xiàn)。
本發(fā)明的特征在所附的權利要求書被詳細指出。通過參考下面的描述并結合所附圖紙可以更好地了解本發(fā)明的上述優(yōu)點和其它優(yōu)點,其中 圖1示出根據(jù)本發(fā)明的一對相鄰打印頭段的示意圖; 圖2顯示了從圖1中所示的相鄰打印頭段打印點的過程; 圖3顯示了在根據(jù)本發(fā)明的打印頭段之間混合點的過程; 圖4顯示了根據(jù)本發(fā)明的實施例的抖動矩陣變化控制的過程; 圖5顯示了根據(jù)本發(fā)明的另一個實施例的抖動矩陣變化控制的過程;以及 圖6以圖形方式顯示了根據(jù)本發(fā)明的另一個實施例所的一個算法,該算法實現(xiàn)了另一種抖動矩陣變化控制的過程。
具體實施例方式
在第一個實例中,通過利用調整相鄰段之間的重疊的數(shù)字處理機制,提供了一種補償相鄰打印頭段的隨溫度變化的相對位移的方法。
在覆蓋A4頁寬的打印頭中可以有10個段,其有9個以交錯對的重復順序設置的重疊部分。使用某種在單片集成電路制造技術領域中公知的技術,可在10微米以內得到段的初始對準。假設段的噴嘴以縱向的“之”字型形式設置在16微米的圓心上,那么6色墨裝置的段寬為225微米左右。
在本實施例中,溫度傳感器被放置在每個打印頭段上,用來提供對每個打印頭段的當前溫度特性的測量。然后,可以利用當前溫度測量確定相鄰打印頭段之間的重疊量。
或者,如果可假設打印頭段的物理特點和性能彼此充分相同,并且每對重疊段的周圍環(huán)境基本相同,則可以只使用單一溫度傳感器。
然后,重疊量被用于提供一種控制相鄰打印頭段之間的半色調的機制。在本發(fā)明中,假設圖像的輸出是借助數(shù)字半色調,所述數(shù)字半色調采用該領域中熟知的任何方法或者技術。很多不同的半色調技術可被利用,參考美國麻省理工學院出版社出版的由Ulichney撰寫的文章“Digital Half Toning”。
如圖1所示,相鄰打印頭段2、3在各自區(qū)域12、13中重疊。對于1600dpi分辨率,重疊區(qū)域可擴展大約千分之四十(~1毫米),提供64個間隔16微米的噴嘴的重疊。在段2的區(qū)域10中,該段噴嘴專用于噴墨。同樣,段3的區(qū)域11中該段的噴嘴專用于噴墨。在重疊區(qū)域12、13中,兩個打印頭段2、3之間提供“混合”,因此,沿打印頭段2的邊緣14,噴嘴專用于在區(qū)域12中打印,同樣,沿邊緣15,段3的噴嘴也幾乎專用于打印。在其間,可為線性或者其它的插值被提供在兩個極端位置之間。因此,如圖2所示,當在頁上打印全色輸出時,17側的區(qū)域由打印頭段10獨立打出,而區(qū)域18由打印頭段11獨立打出(如圖上的黑色點所示),而區(qū)域19包含所述兩個段的噴嘴之間的混合。這種打印方法利用任何公知的半色調矩陣,如上述參考中公開的。雖然已知的半色調矩陣被利用,但是實際利用的打印頭段取決于重疊段之間的重疊量所提供的混合比。
圖3中顯示了一種這樣的方法,其中,重疊區(qū)域內的線性插值被示出。在邊緣14處相應于重疊部分12的區(qū)域中,打印頭段2的噴嘴的利用率為100%,而在打印頭段3的等價區(qū)域,邊緣7,為0輸出。當重疊區(qū)域的距離從段2的行14向段3的行15增加時,部分12的噴嘴的利用率逐漸下降(線性),在邊緣9上為0;部分13的噴嘴的利用率逐漸增加到1,直到邊緣15被到達時。在第一實施例中,其中噴嘴之間有被增加的重疊,所以在重疊區(qū)域中所利用的半色調閥值被增加。這樣減少在混合區(qū)域中打印的點數(shù)。反之,如果打印頭段被間隔開略大于正??山邮艿拈g隔,重疊降低,則可以通過降低半色調閥值增加點頻率。
全面概括的半色調裝置可被提供,如圖4所示,其抖動矩陣25向求和裝置27輸出一個當前抖動值26,而其求和裝置27具有另一個輸入28,該輸入28是一個重疊信號,它根據(jù)相鄰段間的重疊量在正的或負的意義上變動。求和裝置或加法器27的輸出值29通過比較器30與輸入連續(xù)色調數(shù)據(jù)32比較,以輸出半色調數(shù)據(jù)31。一種可替代的裝置允許在施加抖動前從連續(xù)色調數(shù)據(jù)29中減去數(shù)據(jù)值28,產(chǎn)生類似結果。裝置被在圖5中示處。
如圖5所示,通過在加法器46中把抖動矩陣40的輸出42與疊加信號44組合,且然后取得加法器46的輸出54和減法器50的連續(xù)色調數(shù)據(jù)48的差,可以產(chǎn)生半色調數(shù)據(jù)輸出52。這是圖4的等效裝置。
通過利用上述裝置,如圖3和圖4以上所述,可以提供對疊加混合的一定程度的控制,以減少相鄰打印頭段之間的條紋假象的產(chǎn)生。
由于每個疊加信號28可乘以校準因子并被加至校準偏移因子,相鄰打印頭段的位置的精確程度也可被顯著降低。因此,在制造中,相鄰打印頭段可以粗略地彼此對準。然后,可以在已知溫度下打印出測試圖案,以確定相鄰段的噴嘴之間的重疊度。一旦針對特定溫度范圍的重疊度被確定,可以向可編程ROM存儲設備寫入一系列相應值,以便按需提供全部偏移值,其被各自地使用換算因數(shù)換算為打印頭段重疊。
本發(fā)明的另一個實例中涉及用于減少打印頭的重疊段之間的假象的產(chǎn)生的軟件解決方案。抖動矩陣的完整的軟件實現(xiàn)被附在附錄A,包括為調整打印頭段之間的可變重疊量的算法的實現(xiàn)。該程序是用C語言編寫的。在該領域技術人士的知識內,也可以使用其它已作必要的修正的代碼編寫該算法。該算法的原理被解釋如下。
分散點隨機抖動被用于使用雙值點來再現(xiàn)連續(xù)色調像素值。離散點抖動再現(xiàn)高空間頻率,即幾乎到點分辨率的極限的圖像細節(jié),而同時在被人眼空間集成時再現(xiàn)較低的空間頻率到其完全強度深度。隨機抖動矩陣被設計來成跨頁平鋪時免于令人不快的低頻率圖案。
可以使用點增益技術對點疊加建模。點增益是指從點圖案的理想強度到打印圖案時產(chǎn)生的實際強度的增加。在噴墨打印中,點增益主要是由墨洇滲(bleed)引起的。洇滲本身是墨和打印媒質的特性的作用。顏料墨會在表面洇滲,但是向媒質內部不會擴散甚遠?;谌玖系哪梢匝孛劫|內部的纖維素纖維擴展。表面涂層可用于減少洇滲。
由于點重疊效應以與點增益效應相同的方式對點分布敏感,所以把理想點的模型建立為完美地鋪在頁面而不存在重疊是有用的。雖然實際的噴墨點是近似圓的,并且與其相鄰點重疊,但可用正方為理想點建模型。因此,理想和實際點的形狀成為點增益參數(shù)。
點增益是邊緣效應,也就是說,其本身出現(xiàn)在沿已打印點和相鄰未打印點區(qū)域之間的邊緣上。點增益與點圖案的邊緣連接和點圖案的區(qū)域之間的比成比例。處理點增益的兩種技術是分散點抖動和聚集點抖動。在離散點抖動中,點在某個區(qū)域中均勻分布,例如,對于50%強度的點,可使用棋盤格圖案。在聚集點抖動技術中,點由單個中心的“著色”區(qū)域和“未著色”的邊表示,其中,“著色”區(qū)域與“未著色”區(qū)域的比等于要打印的點的強度。因此,分散點抖動比聚集點抖動對點增益更敏感。
兩個相鄰的打印頭段具有若干個重疊的噴嘴。一般來說,相鄰段中的相應噴嘴之間沒有完美的對齊。在局部級別上,可能存在半個噴嘴間隔左右的位置不正,即在1600dpi下為8微米左右。在較高的級別上,重疊噴嘴的數(shù)量實際上可變動。
平滑混合跨重疊橋和從一個段到下一個的輸出的第一方法包括混合從一個到另一個跨重疊區(qū)域的到兩個段的連續(xù)色調輸入。當輸出跨重疊區(qū)域進行時,第二個段接收增加的比例的輸入連續(xù)色調值,而第一個段接收相應減少的比例如以上圖3所述。可以使用線性插值或更高階的插值。則,用于抖動通過上述兩個段輸出的抖動矩陣然后在噴嘴級別上被對齊。
第一方法有兩個缺點。第一,如果特定點位置的抖動閾值低于兩個段的插值連續(xù)色調值,那么兩個段都會為該位置產(chǎn)生一個點。由于該兩點會重疊,所以兩個抖動矩陣所保證的強度只能部分再現(xiàn),導致總體強度的損失。這可通過確保相應的噴嘴決不兩者都產(chǎn)生點來糾正。這也可以通過使用用于交替段的抖動矩陣的逆,或者通過單個抖動矩陣抖動連續(xù)色調值,然后根據(jù)當前插值因子給出的概率,把輸出點隨機地分配給一個或另一個噴嘴來完成。
第二個缺點是,由不同段打印的相鄰點會再次重疊,導致總體強度的損失。
如圖6所示,每個重疊段的值沿水平軸60,62被表示為VA和VB,其各自在值0.0到1.0之間。計算后的輸出66關于垂直軸64被表示為函數(shù)IA+B,針對范圍從0.0到1.0的值。一個等高面顯示了IA+B=0.5的結果值。
圖6示出把兩個段的輸入連續(xù)色調值VA和VB與所觀察到的輸出強度IA+B鏈接起來的三維函數(shù)的定性的形狀。對于第一方法,輸入連續(xù)色調值V和插值因子f共同產(chǎn)生VA=(1-f)V和VB=fV。插值因子越接近0.5,輸入連續(xù)色調值和所觀察到的輸出強度之間的差越大。對于V=1.0,其在圖6中由垂直VA+VB=1.0平面的曲線200示出。通過定義,該曲線位于函數(shù)表面上。圖6顯示,當任何形式的混合出現(xiàn)時,即0.0<f<1.0,輸出強度被削弱。為了實現(xiàn)所需的輸出強度,兩個段的輸入值的和必須超出所需的輸出值,即VA+VB>V。這形成附錄A中的算法的原理。
當只有一個段有助于輸出時,該函數(shù)顯示線性響應,即f=0.0或f=1.0。當然,這假定抖動矩陣包含點增益效應。
上述描述只限于闡述本發(fā)明的特定實例。但是,顯然可對本發(fā)明進行改變和修改,達到本發(fā)明一些或者全部優(yōu)點。例如,將理解,本發(fā)明可在合適的編程數(shù)字數(shù)據(jù)處理系統(tǒng)中被嵌入硬件或者軟件,這兩者可由相關領域的普通技術人員容易地完成。因此,所附的權利要求的目的在于將所有這樣的變化和修改包括在本發(fā)明的實際精神和范圍內。
static void ObtainMisregistrationTransferFunction ( int dotsPerPixel, int subdotsPerDot, BI_Image const& dotImage, char const* pDotImageName, char const* pRefDotImageName, int const overlapSize,<!-- SIPO <DP n="9"> --><dp n="d9"/> int const overlapIndex,//0..overlapSize-1 int const misregFactor, BI_Image const& ditherMatrix, BI_LUT& lutv, BI_LUT& lut0, BI_LUT& lut1);class RLE_DotLine{public RLE_DotLine() m_whiteRun(0),m_blackRun(0){} RLE_DotLine(int whiteRun,int blackRun) m_whiteRun(whiteRun),m_blackRun(blackRun){} intWhiteRun()const{return m_whiteRun;} intBlackRun()const{return m_blackRun;}private intm_whiteRun; intm_blackRun;};typedef vector<RLE_DotLine,allocator<RLE_DotLine>>RLE_Dot;staticvoidUsage(){ fprintf(stderr,″usageSegmentDither\n″); fprintf(stderr,″ inputImage\n″); fprintf(stderr,″ dotsPerPixel\n″); fprintf(stderr,″ subdotsPerDot\n″); fprintf(stderr,″ dotImage\n″); fprintf(stderr,″ refDotImage\n″); fprintf(stderr,″ overlapCenter\n″); fprintf(stderr,″ overlapSize\n″); fprintf(stderr,″ misregFactor\n″); fprintf(stderr,″ ditherMatrix\n″); fprintf(stderr,″ outputImage\n″); fprintf(stderr,″ outputResolution\n″); exit(1);}<!-- SIPO <DP n="10"> --><dp n="d10"/>staticvoidBadArgument(char const* pErrorMsg){ fprintf(stderr,″SegmentDitherargument error%s\n″,pErrorMsg); exit(1);}#define CHECK_ARGUMENT(cond)if(cond) BadArgument(#cond)staticdoubleMisregDots(int const misregFactor){ return(double)misregFactor/1000;}staticintMisregSubdots(int const misregFactor,int const subdotsPerDot){ return(int)BU_Round(MisregDots(misregFactor)*subdotsPerDot);}staticvoidPutDot( int const subdotsPerDot, RLE_Dot const& rleDot, int const dotRow, int const dotCol, int const misregFactor, BI_Image& outputImage){int const misregSubdots=MisregSubdots(misregFactor,subdotsPerDot); int const subdotRow=dotRow*subdotsPerDot; int const subdotCol=dotCol*subdotsPerDot; int const dotOverlap=rleDot.size()-subdotsPerDot; int const dotMargin=dotOverlap/2;<!-- SIPO <DP n="11"> --><dp n="d11"/> RLE_Dot∷const_iterator ii=rleDot.begin(); for(int i=0;i<rleDot.size();i++,ii++) { int const row=subdotRow-dotMargin+i; if(row<0‖row>=outputImage.Height()) continue; int const whiteRun=(*ii).WhiteRun(); int blackRun=(*ii).BlackRun(); int col=subdotCol-dotMargin+whiteRun+misregSubdots; if(col<0) { blackRun+=col; col=0; } if(col+blackRun>=outputImage.Width()) blackRun=outputImage.Width()-col; if(blackRun<=0) continue; BU_ExpandBitRun ( outputImage.Image(row), col, outputImage.Width(), blackRun, 1 ); }}staticvoidMergeScale( double const scale, int& v, double& f0, double& f1){<!-- SIPO <DP n="12"> --><dp n="d12"/> double const vScaled=(double)v*scale; if(vScaled<=255.0) { v=(int)BU_Round(vScaled); } else { v=255; double const fScale=vScaled/255.0; f0*=fScale; f1*=fScale; }}staticvoidDither( BI_Image const& inputImage, BI_LUT const& lutDotGain, int const dotsPerPixel, int const subdotsPerDot, BI_Image const& dotImage, char const*pDotImageName, char const*pRefDotImageName, int const overlapCenter, int const overl.apSize, int const misregFactor, BI_Image const& ditherMatrix, BI_Image& outputImage, int const outputResolution, bool const bRetain, bool const bSklpLHS, bool const bSk.pRHS, bool const bFixedInterp=false, double const flxedF0=0, double const flxedF1=0){ ∥compute overlap interval int const overl.apStart=overlapCenter-(overlapSize/2); int const overLapEnd=overlapStart+overlapSize-1;<!-- SIPO <DP n="13"> --><dp n="d13"/>//copy and invert dither matrixBI_Image ditherMatrix2;ditherMatrix2=ditherMatrix;BI_Invert(ditherMatrix2);//initialise and clear output imageint const subdotsPerPixel=dotsPerPixel*subdotsPerDot;int const bilevelHeight=inputImage.Height()*subdotsPerPixel;int const bilevelWidth=inputImage.Width()*subdotsPerPixel;if (!bRetain){ //initialise outputImage.Initialise ( BI_ColorModel(BI_ColorGrayscale,1), bilevelHeight, bilevelWidth, outputResolution, outputResolution }; //clear BI_CC*pOutputRow=outputImage.Image(); for(int j=0;j<outputImage.Height();j++) { BU_ClearLine(pOutputRow,outputImage.Width()); pOutputRow+=outputImage.RowSize(); }}//convert dot image to RLERLE Dot rleDot;for(int i=0;i<dotImage.Height();i++){ int const whiteRun=BU GetBitRun ( dotImage.Image(i), 0, dotImage.Width(), 0// white ); int blackRun; if(whiteRun==dotImage.Width())<!-- SIPO <DP n="14"> --><dp n="d14"/> { blackRun=0; } else { blackRun=BU_GetBitRun ( dotImage.Image(i), whiteRun, dotImage.Width(), 1//black ); } rleDot.push_back(RLE_DotLine(whiteRun,blackRun)); } //dither contone input image to bi-level output image I_CC const*pImage=inputImage.Image(); BI_CC const*pRow=pImage; BI_CC const*pDither=ditherMatrix. Image(); BI_CC const*pDitherRow=pDither; BI_CC const*pDither2=ditherMatrix2.Image(); BI_CC const*pDitherRow2=pDither2; int ditherRow=0; for(int row=0;row<inputImage.Height();row++) { for(int dotRow=0;dotRow<dotsPerPixel;dotRow++) { int const globalDotRow=(row*dotsPerPixel)+dotRow; BI_CC const*pPixel=pRow; BI_CC const*pDitherPixel=pDitherRow; BI_CC const* pDitherPixel2=pDitherRow2; int ditherCol=0; for(int col=0;col<inputImage.Width();col++) { int const vRaw=*pPixel++; int const vDotGain=lutDotGain[vRaw]; for(int dotCol=0;dotCol<otsPerPixel;dotCol++) { int vRawDot=vRaw; int const t0=*pDitherPixel; int const t1=t0;//*pDitherPixel2;<!-- SIPO <DP n="15"> --><dp n="d15"/> int const globalDotCol=(col*dotsPerPixel)+dotCol; //interpolate intensities in overlapregion and dither //one or the other or both if(!bFixedInterp && globalDotCol<overlapStart) { int const t=t0; if((vDotGain==255)‖(vDotGain>=t && vDotGain?。?)) { if(!bSkipLHS) { PutDot ( subdotsPerDot, rleDot, globalDotRow, globalDotCol, 0, outputImage ); } } } else if(!bFixedInterp && overlapEnd<globalDotCol) { int const t=(overlapSize==0)?t0t1; if((vDotGain==255)‖(vDotGain>=t && vDotGain?。?)) { if(!bSkipRHS) { PutDot ( subdotePerDot, rleDot,<!-- SIPO <DP n="16"> --><dp n="d16"/> globalDotRow, globalDotCol, misregFactor, outputImage ); } } } else {#if 1 //account for stretch or shrink if(!bFixedInterp) { double const misregDots=MisregDots(misregFactor); double const newOverlapSize=overlapSize+misregDots; double const overlapScale=newOverlapSize/overlapSize; vRawDot=(int)BU_Round(vRawDot*overlapScale); if(vRawDot>255) vRawDot=255; //MergeScale(overlapScale,vRawDot,f0,f1); }#endif#if 1 //compute interpolation factors double f0,f1; if(bFixedInterp) { f0=fixedF0; f1=fixedF1; } else { //compute overlap index int const overlapIndex=<!-- SIPO <DP n="17"> --><dp n="d17"/> globalDotCol-overlapStart; //obtain misregistration LUTs BI_LUT lutv; BI_LUT lut0; BI_LUT lut1; ObtainMisregistrationTransferFunction ( dotsPerPixel, subdotsPerDot, dotImage, pDotImageName, pRefDotImageName, overlapSize, overlapIndex, misregFactor, ditherMatrix, lutv, lut0, lut1 ); //retrieve interpolationfactors f0=(double)lut0[vRawDot]/255; f1=(double)lut1[vRawDot]/255; if(globalDotCol>overlapCenter) BU_Swap(f0,f1); //adjust intensity forattenuation vRawDot=lutv[vRawDot]; }#endif //diagnostics //printf(″f0=%5.1lf f1=%5.1lf(%5.1lf)vRaw=%d v=%d\n″,<!-- SIPO <DP n="18"> --><dp n="d18"/> //f0,f1,f0+f1,vRaw,vRawDot); //interpolate dither with jitter int vd=0; int v0d=0; int v1d=0; if((vRawDot==255)‖(vRawDot>=t0&& vRawDot?。?)) { vd=1; } double const rr=(double)rand()/RAND_MAX; if (vd && rr<f0) { v0d=1; if(!bSkipLHS) { PutDot ( subdotsPerDot, rleDot, globalDotRow, globalDotCol, 0, outputImage ); } } if(vd && (1.0-rr)<=f1) { v1d=1; if(!bSkipRHS) { PutDot ( subdotsPerDot, rleDot, globalDotRow, globalDotCol,<!-- SIPO <DP n="19"> --><dp n="d19"/> misregFactor, outputImage ); } }#if 0 if(globalDotRow==864) { printf(″%1d %1d %1d(%3d %3d%3d %3d)″, vd,v0d,v1d,vRawDot,v0,v1,v0+v1); if(v0d+v1d<vd) printf(″?″); if(v0d+v1d>vd) printf(″#″); printf(″\n″); }#endif } pDitherPixel++; pDitherPixel2++; ditherCol++; if(ditherCol>=ditherMatrix.Width()) { pDitherPixel=pDitherRow; pDitherPixel2=pDitherRow2; ditherCol=0; } } } pDitherRow+=ditherMatrix.RowSize(); pDitherRow2+=ditherMatrix2.RowSize(); ditherRow++; if(ditherRow>=ditherMatrix.Height()) { pDitherRow=pDither; pDitherRow2=pDither2; ditherRow=0; } } pRow+=inputImage.RowSize();<!-- SIPO <DP n="20"> --><dp n="d20"/> }}staticvoidChangeFileSuffix( char const*pPath, char const*pSuffix, char const*pExt, char path[_MAX_PATH]}{ char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; _splitpath(pPath,drive,dir,fname,ext); strcat(fname,pSuffix); _makepath(path,drive,dir,fname,pExt);}staticvoidLogTransferFunction(char const*pType,double const intensity[],int const v){ printf(″%s%03d%5.1lf(%5.1lf)\n″, pType,v,intensity[v],v-intensity[v]);}staticvoidComputeMisregistrationTransferFunction( int dotsPerPixel, int subdotsPerDot, BI_Image const& dotImage, char const*pDotImageName, double const f0, double const f1, int const misregFactor, BI_Image const& ditherMatrix, BI_LUT& lutv,<!-- SIPO <DP n="21"> --><dp n="d21"/> BI_LUT& lut0, BI_LUT& lut1}{ //create test image BI_Image testImage; testImage.Initialise ( BI_ColorModel(BI_ColorGrayscale), ditherMatrix.Height(), ditherMatrix.Width() ); //build identity transfer function BI_LUT identityLut; for(int v=0;v<256;v++) identityLut[v]=v; //create output image BI_Image outputImage; //compute intensity for each gray level double intensity[512]; int vLast; for(v=0;v<512;v++) { //compute extended interpolation factors double f0x,f1x; int vx; if(v<=255) { vx=v; f0x=f0; fix=f1; } else { vx=255; double const fScale=(double)v/255.0; f0x=f0*fScale; f1x=f1*fScale; }<!-- SIPO <DP n="22"> --><dp n="d22"/> //set test image to next intensity testImage=BI_Color((BI_CC)vx); //dither test image to bi-level output Dither { testImage, identityLut, dotsPerPixel, subdotsPerDot, dotImage, pDotImageName, pDotImageName, 0,0, //no explicit overlap misregFactor, ditherMatrix, outputImage, 72, //output resolution false, //don′t retain output image false, //don′t skip LHS false, //don′t skip PHS true, //fixed interpolation f0x, f1x}; //determine intensity of dithered bi-level output long nDots=0; BI_CC const*pRow=outputImage.Image(); for(int row=0;row<outputImage.Height();row++) { nDots+=BU_CountBits(pRow,0,outputImage.Width()); pRow+=outputImage.RowSize(); } intensity[v]=255*(double)nDots/outputImage.PixelCount(); //LogTransferFunction(″misreg″,intensity,v); vLast=v; if(intensity[v]>=255) break;}LogTransferFunction(″misreg″,intensity,1);LogTransferFunction(″misreg″,intensity,vLast);<!-- SIPO <DP n="23"> --><dp n="d23"/> //create LUTs for(int x=0;x<256;x++) { double d=-1; for(v=0;v<=vLast;v++) { double const d2=BU_Abs(intensity[v]-x); if (d<0‖d2<d) { d=d2; if(v<=255) { lutv[x]=v; int const k0=(int)BU_Round(f0*255); lut0[x]=(BI_CC)BU_Min(k0,255); int const k1=(int)BU_Round(f1*255); lut1[x]=(BI_CC)BU_Min(k1,255); } else { lutv[x]=255; int const k0=(int)BU_Round(f0*v); lut0[x]=(BI_CC)BU_Min(k0,255); int const k1=(int)BU_Round(f1*v); lut1[x]=(BI_CC)BU_Min(k1,255); if(k0>255‖k1>255) { fprintf(stderr,″k0=%d k1=%d (x=%dv=%d f0=%5.1lf f1=%5.1lf\n″, k0,k1,x,v,f0,f1); } } } } }}staticvoidSimplifyFraction(int& n,int& d){ for(int i=n;i>1&& n>1;--i)<!-- SIPO <DP n="24"> --><dp n="d24"/> { if((d%i)==0) { if((n%i ==0) { n/=i; d/=i; } } }}staticvoidObtainMisregistrationTransferFunction<br/>{ int dotsPerPixel, int subdotsPerDot, BI_Image const& dotImage, char const*pDotImageName, char const*pRefDotImageName, int const overlapSize, int const rawOverlapIndex,//0.. overlapSize-1 int const misregFactor, BI_Image const& ditherMatrix, BI_LUT& lutv, BI_LUT& lut0, BI_LUT& lut1{ //normalize overlap index int overlapIndex=rawOverlapIndex; if(overlapIndex>=((overlapSize+1)/2)) overlapIndex=(overlapSize-1)-overlapIndex; char lutvName[_MAX_PATH]; char lut0Name[_MAX_PATH]; char lutlName[_MAX_PATH]; char suffix[_MAX_FNAME]; int interpNum=overlapIndex+1; int interpDenom=overlapSize+1; SimplifyFraction(interpNum,interpDenom);<!-- SIPO <DP n="25"> --><dp n="d25"/>sprintf(suffix,″_%03d_%02d_%02d″, BU_Abs(misregFactor),interpNum,interpDenom);ChangeFileSuffix(pRefDotImageName,suffix,″.amp″,lutvName);sprintf(suffix,″_%03d_%02d_%02d_0″, BU_Abs(misregFactor),interpNum,interpDenom);ChangeFileSuffix(pRefDotImageName,suffix,″.amp″,lut0Name);sprintf(suffix,″_%03d_%02d_%02d_1″, BU_Abs(misregFactor),interpNum,interpDenom);ChangeFileSuffix(pRefDotImageName,suffix,″.amp″,lut1Name);try{ BU_File lutvFile(lutvName,_O_BINARY|_O_RDONLY); lutv.Load(lutvFile); BU_File lut0File(lut0Name,_O_BINARY|_O_RDONLY); lut0.Load(lut0File); BU_File lut1File(lut1Name,_O_BINARY|_O_RDONLY); lut1.Load(lut1File);}catch (...){ //if using a reference dot image,LUTs must already exist if(strcmp(pDotImageName,pRefDotImageName)!=0) { fprintf(stderr,″can′t load %s or %s or %s\n″, lutvName,lut0Name,lut1Name); exit(1); } //determine interpolation factors double f1=(double)interpNum/interpDenom; double f0=1.0-f1; ComputeMisregistrationTransferFunction ( dotsPerPixel, subdotsPerDot, dotImage, pDotImageName, f0,<!-- SIPO <DP n="26"> --><dp n="d26"/> f1, BU_Abs(misregFactor), ditherMatrix, lutv, lut0, lut1 ); BU_File lutvFile(lutvName,_O_BINARY|_O_WRONLY|_O_CREAT); lutv. Save(lutvFile); BU_File lut0File(lut0Name,_O_BINARY|_O_WRONLY|_O_CREAT); lutO.Save(lut0File); BU_File lut1File(lutlName,_O_BINARY|_O_WRONLY|_O_CREAT); lutl.Save(lut1File); }}staticvoidComputeDotGainTransferFunction( int dotsPerPixel, int subdotsPerDot, BI_Image const& dotImage, char const*pDotImageName, BI_Image const& ditherMatrix, BI_LUT& lutDotGain){ //create test image BI_Image testImage; testImage. Initialise ( BI_ColorModel(BI_ColorGrayscale), ditherMatrix.Height(), ditherMatrix.Width() ); //build identity transfer function BI_LUT identityTransferFunction; for(int v=0;v<256;v++) identityTransferFunction[v]=v; //create output image<!-- SIPO <DP n="27"> --><dp n="d27"/>BI_Image outputImage;//compute intensity for each gray leveldouble intensity[256];for(v=0;v<256;v++){//set test image to next intensitytestImage=BI_Color((BI_CC)v);//dither test image to bi-level outputDither(testImage,identityTransferFunction, dotsPerPixel, subdotsPerDot, dotImage, pDotImageName, pDotImageName, 0,0, //no overlap 0, //nomisregistration ditherMatrix, outputImage, 72, //outputresolution false,//don′t retain outputimage false,//don′t skip LHS false //don′t skip RHS ); //determine intensity of dithered bi-level output long nDots=0; BI_CC const*pRow=outputImage.Image(); for(int row=0;row<outputImage.Height();row++){ nDots+=BU_CountBits(pRow,0,outputImage.Width()); pRow+=outputImage.RowSize(); } intensity[v]=255*(double)nDots/outputImage.PixelCount(); //LogTransferFunction(″dot gain″,intensity,v); }<!-- SIPO <DP n="28"> --><dp n="d28"/>LogTransferFunction(″dot gain″,intensity,1); LogTransferFunction(″dot gain″,intensity,255); //create LUT for(int x=0;x<256;x++) { double d=-1; for(v=0;v<256;v++) { double const d2=BU_Abs(intensity[v]-x); if(d<0‖d2<d} { d=d2; lutDotGain[x]=v; } } }}staticvoidObtainDotGainTransferFunction( int dotsPerPixel, int subdotsPerDot, BI_Image const& dotImage, char const*pDotImageName, char const*pRefDot ImageName, BI_Image const& ditherMatrix, BI_LUT& lutDotGain){ char lutName[_MAX_PATH]; ChangeFileSuffix(pRefDotImageName,″″,″.amp″,lutName); try { BU_File lutFile (lutName,_O_BINARY|_O_RDONLY); lutDotGain. Load(lutFile); } catch (...) { //if using a reference dot image,LUT must already exist if(strcmp(pDotImageName,pRefDotImageName) ?。?)<!-- SIPO <DP n="29"> --><dp n="d29"/> { fprintf(stderr,″can′t load %s\n″,lutName); exit(1); } ComputeDotGainTransferFunction ( dotsPerPixel, subdotsPerDot, dotImage, pDotImageName, ditherMatrix, lutDotGain );BU_File lutFile(lutName,_O_BINARY|_O_WRONLY|_O_CREAT); lutDotGain.Save(lutFile); }}staticvoidSegmentDither(int argc,char*argv[]){ //parse arguments if(argc?。?2) Usage(); char const*pInputImageName=argv[1]; int const dotsPerPixel=atoi(argv[2]); int const subdotsPerDot=atoi(argv[3]); char const*pDotImageName=argv[4]; char const*pRefDotImageName=argv[5]; int const overlapCenter=atoi(argv[6]); int const overlapSize=atoi(argv[7]); int const misregFactor=atoi(argv[8]); int const misregSubdots=MisregSubdots(misregFactor,subdotsPerDot); char const*pDitherMatrixName=argv[9]; char const*pOutputImageName=argv[10]; int const outputResolution=atoi(argv[11]); //open input image BI_Image inputImage; BI_LoadImage(inputImage,pInputImageName); CHECK_ARGUMENT(inputImage.ColorModel()1=BI_ColorModel(BI_ColorGrayscale));<!-- SIPO <DP n="30"> --><dp n="d30"/> BI_Invert(inputImage);// max is black BI_TIFFSetMinIsBlack(false);// max is black // check arguments CHECK_ARGUMENT(dotsPerPixel<1); CHECK_ARGUMENT(dotsPerPixel>16); CHECK_ARGUMENT(subdotsPerDot<1); CHECK_ARGUMENT(subdotsPerDot>32); CHECK_ARGUMENT(overlapCenter<1); CHECK_ARGUMENT(overlapCenter>=inputImage.Width()*dotsPerPixel); CHECK_ARGUMENT(overlapSize<0); CHECK_ARGUMENT(misregSubdots<-subdotsPerDot/2); CHECK_ARGUMENT(misregSubdots>subdotsPerDot/2); CHECK_ARGUMENT(outputResolution<=0); //diagnostics printf(″misregSubdots=%d\n″,misregSubdots); //open dot image BI_Image dotImage; BI_LoadImage(dotImage,pDotImageName); CHECK_ARGUMENT(dotImage.ColorModel()?。紹I_ColorModel(BI_ColorGrayscale,1)); CHECK_ARGUMENT(dotImage.Height()<subdotsPerDot); CHECK_ARGUMENT(dotImage.Width()<subdotsPerDot); CHECK_ARGUMENT(dotImage.Height()?。絛otImage.Width()); int const dotOverlap=dotImage.Width()-subdotsPerDot; CHECK_ARGUMENT((dotOverlap%2)1=0); //open dither matrix BI_Image ditherMatrix; BI_LoadImage(ditherMatrix,pDitherMatrixName); CHECK_ARGUMENT(ditherMatrix. ColorModel()!=BI_ColorModel(BI_ColorGrayscale,8)); CHECK_ARGUMENT(ditherMatrix.Height()<16); CHECK_ARGUMENT(ditherMatrix.Width()<16); //create output image BI_Image outputImage; //obtain dot gain transfer function for particular dot shape BI_LUT lutDotGain; ObtainDotGainTransferFunction<!-- SIPO <DP n="31"> --><dp n="d31"/>( dotsPerPixel, subdotsPerDot, dotImage, pDotImageName, pRefDotImageName, ditherMatrix, lutDotGain);//dither input to bi-level outputDither( inputImage, lutDotGain, dotsPerPixel, subdotsPerDot, dotImage, pDotImageName, pRefDotImageName, overlapCenter, overlapSize, misregFactor, ditherMatrix, outputImage, outputResolution, false, //don′t retain output image false, //don′t skip LHS false//don′t skip RHS);BI_SaveImage(outputImage,pOutputImageName);//dither input to bi-level output (LHS only)BI_Image outputImageLHS;Dither( inputImage, lutDotGain, dotsPerPixel, subdotsPerDot, dotImage, pDotImageName, pRefDotImageName,<!-- SIPO <DP n="32"> --><dp n="d32"/> overlapCenter, overlapSize, misregFactor, ditherMatrix, outputImageLHS, outputResolution, false,//don′t retain output image false,//don′t skip IHS true //skip RHS);BI_SaveImage(outputImageLHS,″OutLHS.tif″);//dither input to bi-level output(RHS only)BI_Image outputImageRHS;Dither( inputImage, lutDotGain, dotsPerPixel, subdotsPerDot, dotImage, pDotImageName, pRefDotImageName, overlapCenter, overlapSize, misregFactor, ditherMatrix, outputImageRHS, outputResolution, false,//don′t retain output image true, //skip LHS false //don′t skip RHS);BI_SaveImage(outputImageRHS,″OutRHS.tif″);//dither input to bi-level output (no interp)BI_Image outputImageNoInterp;Dither( inputImage, lutDotGain, dotsPerPixel, subdotsPerDot,<!-- SIPO <DP n="33"> --><dp n="d33"/> dotImage, pDotImageName, pRefDotImageName, overlapCenter, overlapSize, misregFactor, ditherMatrix, outputImageNoInterp, outputResolution, false, //don′t retain output image false, //skip LHS false, //don′t skip RHS true,//fixed interp 0, //f0 0 //f1 ); BI_SaveImage(outputImageNoInterp,″OutNoInterp.tif″);}voidmain(int argc,char * argv[]){ try { SegmentDither(argc,argv); } catch (BU_Error error) { error. Print(); } exit(0);}。
權利要求
1.一種包括噴墨打印頭的打印機,所述噴墨打印頭包括多個在空間上間隔開的重疊的打印頭段;所述打印機進一步包括至少一個用于測量相鄰打印頭段之間的重疊度的裝置;用于提供連續(xù)色調圖象的半色調的裝置,以及用于調節(jié)相鄰打印頭段之間的重疊區(qū)內的所述半色調裝置的裝置,以減小所述相鄰段之間的假象。
2.根據(jù)權利要求1中所述的打印機,其中所述至少一個用于測量相鄰打印頭段之間重疊度的裝置包括用于測量所述相鄰打印頭段的溫度的裝置。
3.根據(jù)權利要求1中所述的打印機,其中所述至少一個測量相鄰打印頭段之間重疊量的裝置包括用于測量所述相鄰打印頭段的相當位移的裝置。
4.根據(jù)權利要求2中所述的打印機,其中所述用于提供連續(xù)色調圖象的半色調的裝置包括抖動矩陣,且所述用于調節(jié)所述半色調裝置的裝置包括具有兩個輸入的求和裝置,所述一個輸入為所述抖動矩陣的輸出,所述另一個輸入為來源于所述至少一個用于測量相鄰打印頭段之間的重疊度的裝置的重疊信號。
5.根據(jù)權利要求4所述的打印機,還包括一個用于比較所述求和裝置的輸出和連續(xù)色調數(shù)據(jù)輸入的比較器裝置,所述比較器裝置的輸出為用于相鄰打印頭段的相應噴嘴的半色調數(shù)據(jù)。
6.根據(jù)權利要求2中所述的打印機,其中,所述用于調節(jié)相鄰打印頭段之間的重疊區(qū)內的所述半色調裝置的所述裝置包括用于對抖動矩陣求逆用于交替段的裝置。
7.根據(jù)權利要求4中所述的打印機,還包括用于將所述求和裝置的輸出從連續(xù)色調數(shù)據(jù)輸入信號中減去以產(chǎn)生用于驅動相鄰打印頭段的噴嘴的半色調數(shù)據(jù)值的裝置。
全文摘要
一種包括噴墨打印頭的打印機,所述噴墨打印頭包括多個在空間上間隔開的重疊的打印頭段;該打印機進一步包括至少一個用于測量相鄰打印頭段之間的重疊度的裝置;用于提供連續(xù)色調圖象的半色調的裝置和用于調節(jié)相鄰打印頭段之間的重疊區(qū)內的所述半色調裝置的裝置,以減小所述相鄰段之間的假象。
文檔編號B41J2/155GK1672940SQ200510063190
公開日2005年9月28日 申請日期2000年5月24日 優(yōu)先權日2000年5月24日
發(fā)明者卡·西爾弗布魯克, 保羅·拉普斯頓 申請人:西爾弗布魯克研究有限公司