【文献】
牟田 英正 ほか,Cell/B.E.を搭載したゲーム機による家庭内分散処理,コンピュータシステム・シンポジウム論文集,2007年11月27日,第2007巻 第14号,p.49〜58,ISSN 1344-0640
(58)【調査した分野】(Int.Cl.,DB名)
前記Yコンポーネントは前記ソース画像の輝度に対応し、前記Coコンポーネントは前記ソース画像のオレンジに対応し、前記Cgコンポーネントは前記ソース画像の緑に対応することを特徴とする請求項1に記載の方法。
リモートデスクトッププロトコル(RDP)プロトコル経由で前記圧縮画像データをネットワークに送信するステップをさらに備えることを特徴とする請求項1に記載の方法。
ピクセルの各チャネルは8ビットを備え、前記ソース画像の各チャネルを配列することは各チャネルを16ビット配列することを備えることを特徴とする請求項1に記載の方法。
前記分離するステップ、前記変換するステップ、および前記記憶するステップのうちの少なくとも1つの動作は、SIMD命令を前記プロセッサに送信して、少なくとも1つのチャネルのそれぞれが複数のピクセルを同時に動作することを備えることを特徴とする請求項1に記載の方法。
前記CoおよびCgコンポーネントを圧縮するステップは、前記画像を圧縮する量に対応する前記色損失レベルを用いて前記CoおよびCgコンポーネントを圧縮することを備えることを特徴とする請求項1に記載の方法。
前記CoおよびCgコンポーネントを圧縮するステップは、レンペルジフ(LZ)アルゴリズムに従ってランレングス符号化を行うことを備えることを特徴とする請求項1に記載の方法。
前記プロセッサ上で実行されると、少なくとも、前記圧縮画像データを4ピクセルから成る少なくとも1つのグループに分け、4ピクセルから成る各グループをサブサンプリングするステップを前記システムに行わせるプロセッサ実行可能命令を、前記メモリがさらに保持することを特徴とする請求項12に記載のシステム。
【発明を実施するための形態】
【0012】
本明細書の実施形態では、ピクセル用の色チャネルを平面データソースに分割または分離することによって画像のデータ圧縮を強化するための前処理ステージまたは機構を提供する。典型的には、画像データは、画像(ビットマップなど)内の各ピクセルが色チャネルごとに1つのコンポーネントを有するように、色空間用にインタリーブされたチャネルタイプのセットとして表示される。例えば、赤、緑および青(RGB)の色空間を有するピクセルは、赤用に1つの色チャネル、緑用に1つの色チャネル、および青用に1つの色チャネルを有する。それにより、例示的な実施形態は、同様のコンポーネントが同じ平面内で示されるように、各チャネル用のコンポーネントを平面データソースに分離する。インタリーブされたビットマップまたはデジタル画像を平面表示に分離することによって、各平面を独立して圧縮し、しばしば高い圧縮比を実現することができる。これは、特に、大抵の場合ビットマップ全体でほとんど変わらないと見込まれるチャネル(例えば、ビットマップ内の要素の透明度を記述するアルファチャネル)に当てはまる。
【0013】
言い換えれば、例示的な実施形態は、しばしばあるチャネルが遷移され得る一方で、別のチャネルはほとんど変わらないという事実を利用する。チャネルデータの操作を通じてまたは色空間をRGBのため以外の何かに変換することを通じて、上記の実施形態の利用をさらに強化することができる。例えば、照明およびクロミナンスという観点からピクセルを定義する(例えば、YUV、YCoCgなど)他の色空間は、典型的には人間の目がどのように色を認識するかという観点から色空間をより多く記述する。言い換えれば、このようなタイプの色空間は、目がより敏感である色コンポーネントをその目があまり敏感でないチャネルから分離する。これによって、人間の目の知覚の違いを利用することによって、色チャネル内の情報を落として(degrade)圧縮モデルがより効率的に対処することができるパターンを強化することが可能であり、さらにその画像が知覚的にロスレスのままにすることが可能である。
【0014】
本明細書で説明したように、圧縮比を強化するために、特定の色空間またはデジタル画像用の色情報を修正可能にするいくつかの方法があり得る。例えば、特定の色スキームのクロミナンスチャネルを、その特定のチャネルと関連付けられたすべてのビットカウントを減少させることによって量子化できることによって、その色パレットの忠実度が低下するが、必ずしも色スキームの範囲が減少するわけではない。代替的または併用して、さまざまなクロミネンス値のサンプルピクセル空間またはサブサンプリングを全体値のある平均に修正する、およびまたはその値を公分母(common denominator)にもってくる他の同様の修正を行うことができる。以下により詳細に説明するように、圧縮用画像データを前処理する時にパターン認識を強化するようにデータを修正するための他の機構もあり得る。
【0015】
ひとたびデジタル画像またはビットマップが論理的に分離したデジタル画像、即ちチャネル情報の各プレーン用のデジタル画像に分割される、およびひとたびデータのすべての操作または修正が行われると、例示的な実施形態は、二次元ランレングス符号化スキームなどの、標準または周知の符号化モジュールを使用してその値を符号化することができる。各走査線のビットマップを、走査線の前に置いて(precede)その走査線と区別して取り扱うことができ、次に、以下により詳細に説明するように、そのような区別を符号化することができる。
【0016】
本開示の実施形態は、1または複数のコンピュータ上で実行できる。
図1および以下の考察は、本開示を実装できる適切なコンピューティング環境の簡潔な概説を提供することを意図する。当業者は、
図1のコンピュータシステムの一部またはすべてのコンポーネントを使用して、
図3および
図4のコンピュータを達成(effectuate)することができることを認識することができる。
【0017】
本開示を通じて使用される用語、回路は、例えば、ハードウェア割り込みコントローラ、ハードドライブ、ネットワークアダプタ、グラフィックプロセッサ、および音声コーデックなどの専用ハードウェアコンポーネント含むことができる。同じまたは他の実施形態において、回路は、ファームウェアによってまたはセットスイッチによって機能(複数可)を行うように構成されたマイクロプロセッサを含むことができる。同じまたは他の例示的な実施形態において、回路は、例えば、マルチコア汎用処理ユニットの1または複数のコアなどの、1または複数の論理プロセッサを含むことができる。この例の論理プロセッサ(複数可)を、例えば、RAM、ROM、ファームウェア、および/または仮想メモリなどのメモリからロードされる機能(複数可)を行うのに動作可能なロジックを実施するソフトウェア命令によって構成することができる。回路がハードウェアとソフトウェアとの組み合わせを含む例示的実施形態において、メーカー(implementer)は、論理プロセッサによって処理することができるマシン可読コードに後でコンパイルされるロジックを実施するソースコードを書き込むことができる。当業者は、技術の最先端がハードウェア、ソフトウェア、またはハードウェア/ソフトウェアの組み合わせにおいてほとんど区別がつかない所まで進歩していることを認識することができるので、特定の機能を達成するハードウェアかソフトウェアかの選択は、メーカーに任された設計上の選択である。より詳細には、当業者は、ソフトウェア処理は同等のハードウェア構造に転換することができ、ハードウェア構造自体は同等のソフトウェア処理に転換することができることを認識することができる。従って、ハードウェア実装かソフトウェア実装かの選択は、設計上の選択の一つであり、メーカーに任される。
【0018】
図1を参照すると、例示的な汎用コンピューティングシステムが示されている。汎用コンピューティングシステムは、1または複数の論理プロセッサ、システムメモリ22、およびシステムメモリを含むさまざまなシステムコンポーネントを処理ユニット21に接続するシステムバス23を含むことができる汎用処理ユニット21を含む、従来型コンピュータ20などを含むことができる。システムバス23は、メモリバスまたはメモリコントローラ、周辺バス、およびさまざまなバスアーキテクチャを任意に使用したローカルバスを含む、いくつかのタイプのバス構造のいずれにもすることができる。システムメモリは、リードオンリーメモリ(ROM)24およびランダムアクセスメモリ(RAM)25を含む。起動時などの、コンピュータ20内の要素間で情報を転送するのに役立つ基本ルーチンを含む、基本入力/出力システム26(BIOS)は、ROM24に記憶される。コンピュータ20は、図示されないハードディスクの読み取りおよび書き込み用ハードディスクドライブ27、リムーバブル磁気ディスク29の読み取りおよび書き込み用磁気ディスクドライブ28、およびCD−ROMまたは他の光媒体などのリムーバブル光ディスク31の読み取りおよび書き込み用光ディスクドライブ30をさらに含むことができる。ある例示的な実施形態において、本開示の態様を実施するコンピュータ実行可能命令を、ROM24、ハードディスク(図示せず)、RAM25、リムーバブル磁気ディスク29、光ディスク31、および/または汎用処理ユニット21のキャッシュに記憶できる。ハードディスクドライブ27、磁気ディスクドライブ28、および光ディスクドライブ30は、ハードディスクドライブインタフェース32、磁気ディスクドライブインタフェース33、および光ドライブインタフェース34によってそれぞれシステムバス23に接続される。ドライブおよびそれらに関連付けられたコンピュータ可読媒体は、コンピュータ20用のコンピュータ可読命令、データ構造、プログラムモジュールおよび他のデータの不揮発性記憶を提供する。本明細書で説明される例示的な環境は、ハードディスク、リムーバブル磁気ディスク29およびリムーバブル光ディスク31を用いるが、磁気カセット、フラッシュメモリカード、デジタルビデオディスク、ベルヌーイカートリッジ、ランダムアクセスメモリ(RAM)、リードオンリーメモリ(ROM)などのコンピュータによってアクセス可能なデータを記憶することができる他のタイプのコンピュータ可読媒体も例示的なオペレーティング環境に使用できることを当業者は認識されたい。
【0019】
オペレーティングシステム35、1または複数のアプリケーションプログラム36、他のプログラムモジュール37およびプログラムデータ38を含む多数のプログラムモジュールを、ハードディスク、磁気ディスク29、光ディスク31、ROM24またはRAM25上で記憶できる。ユーザは、キーボード40およびポインティングデバイス42などの入力デバイスを通じてコマンドおよび情報をコンピュータ20に入力できる。他の入力デバイス(図示せず)は、マイクロフォン、ジョイスティック、ゲームパッド、衛星放送受信アンテナ、スキャナなどを含むことができる。これらと他の入力デバイスは、システムバスに接続されたシリアルポートインタフェース46を通じて汎用処理ユニット21に接続されることが多いが、パラレルポート、ゲームポートまたはユニバーサルシリアルバス(USB)などの他のインタフェースによっても接続できる。ディスプレイ47または他のタイプのディスプレイデバイスも、ビデオアダプタ48などのインタフェース経由でシステムバス23に接続することができる。ディスプレイ47に加えて、コンピュータは、典型的には、スピーカおよびプリンタなどの他の周辺出力デバイス(図示せず)を含む。
図1の例示的なシステムは、ホストアダプタ55、小型計算機システムインタフェース(SCSI)バス56およびSCSIバス56に接続される外部記憶デバイス62も含む。
【0020】
コンピュータ20は、リモートコンピュータ49などの、1または複数のリモートコンピュータへの論理接続を使用するネットワーク化環境において動作できる。リモートコンピュータ49は、別のコンピュータの、サーバ、ルータ、ネットワークPC、ピアデバイスまたは他の共有ネットワークノードにすることができ、メモリ記憶デバイス50のみが
図1に図示されているが。典型的には、コンピュータ20に対して上述した要素の多くまたはすべてを含むことができる。
図1に示された論理接続は、ローカルエリアネットワーク(LAN)51およびワイドエリアネットワーク(WAN)52を含むことができる。このようなネットワーキング環境は、オフィス、企業規模のコンピュータネットワーク、イントラネットおよびインターネットにおいて当たり前となっている。
【0021】
LANネットワーキング環境に使用される時、コンピュータ20を、ネットワークインタフェースまたはアダプタ53を通じてLAN51に接続することができる。WANネットワーキング環境に使用される時、コンピュータ20は、典型的には、モデム54またはインターネットなどのワイドエリアネットワーク52に通信を確立するための他の手段を含むことができる。モデム54は、内部モデムまたは外部モデムとしてもよく、シリアルポートインタフェース46経由でシステムバス23に接続することができる。ネットワーク化環境において、コンピュータ20またはその一部に対して示されたプログラムモジュールを、リモートメモリ記憶デバイスに記憶できる。図示されたネットワーク接続は例示的であり、コンピュータ間で通信リンクを確立する他の手段も使用できることが認識されよう。さらに、本開示の多数の実施形態は、特にコンピュータ化されたシステムによく適していることが想定されるが、本文書において本開示をそのような実施形態に限定する意図はまったくない。
【0022】
前述の詳細な説明では、例示および/または動作可能な図を介してシステムおよび/またはプロセスのさまざまな実施形態を説明した。その限りにおいてブロック図、および/または例は、1または複数の機能および/または動作を含むが、そのようなブロック図における各機能および/または動作、または例を、広範囲にわたるハードウェア、ソフトウェア、ファームウェア、またはその実質的な任意の組み合わせによって個々におよび/または集合的に実装することができることを当業者には理解されよう。
【0023】
本明細書に説明した本発明の対象の特定の態様について説明してきたが、当業者には当然ながら、本明細書の教示に基づいて、本明細書に説明した本発明の対象およびその幅広い態様から逸脱せずに変更および修正を行うことができるので、添付の特許請求の範囲は、本明細書に説明した本発明の対象の真の精神および範囲と同様に、それらの範囲においてそのようなすべての変更および修正を網羅するものである。
【0024】
図2は、ソース画像を、単一命令複数データ(SIMD)命令セットを備えるプロセッサ上で圧縮するための例示的なオペレーティングプロシージャを示している。SIMD命令セット用いたプロセッサは、一般にベクトルプロセッサとして知られる。ネハレム(商標)プロセッサのような、いくつかのインテル(商標)x86ISAプロセッサ内のSSE4.2命令などのストリーミングSIMD拡張命令(SSE)は、このようなSIMD命令の形式である。このようなプロセッサは、並列形式でデータの大部分に瞬時に動作できる。例えば、このような64ビットプロセッサは、2つの整数を2つの64ビットワードにそれぞれ入れることによって、符号付き32ビット整数の2つのセットを同時に和し、次に各64ビットワードに加えることができる。各ローワードが2∧31を含む場合など、通常ローワードからハイワードへオーバーフローがある場合、その命令は、一般にこれを把握し、ハイワードにオーバーフローしない。このような動作可能なプロシージャを使用して、リモートデスクトッププロトコル(RDP)などを経由して、ネットワークに送信する画像を圧縮できる。このような実施形態において、ソース画像および出力画像は、動作するプロシージャが実行されるコンピュータにおいてローカルの場合でもユーザが体験するなどで表示されたユーザセッションに対応できる。その表示されたユーザセッションは、コンピュータデスクトップだけでなくユーザがそのコンピュータにおいて見るような方法でタイル表示された任意のオープンアプリケーションウィンドウも含むことができる。
【0025】
実施形態において、ソース画像は、ピクセルの行および列を備え、各ピクセルは、ピクセル用の赤(R)色値、緑(G)色値、青(B)色値およびアルファ(A)(または透明度)値のそれぞれに8ビットが当てられるように、RGBA色空間内に32ビットを備える。
【0026】
動作200は、その方法から開始する。例えば、その画像を圧縮する命令に沿ってソース画像を受信すると、それを実行できる。
【0027】
動作202は、ソース画像の各チャネルを16ビット配列することを示しており、ソース画像は少なくとも1ピクセルを備え、各ピクセルは赤(R)値、緑(G)値、青(B)値およびアルファ(A)値を備える。これは、そのソース画像のメモリ内の位置が16バイトの倍数であるアドレス内にあるか確認し、次に、すべてのピクセルが8ビットであるか、次に、メモリ空間内に8ビット配列されているかを確認することを備える。
【0028】
動作204は、ソース画像を平坦化してRベクトル、GベクトルおよびBベクトルを作り出すことを示しており、Rベクトルは各ピクセルのR値を備え、Gベクトルは各ピクセルのG値を備え、Bベクトルは各ピクセルのB値を備える。1番目のピクセルの赤値がR(1)になるようにピクセルの色値が表されている場合、n個のピクセルのソース画像は、初めのうちはR(1)G(1)B(1)A(1)R(2)G(2)B(2)A(2)...R(n)G(n)B(n)A(n)の形をとると考えることができる。ソース画像の平坦化において、そのような各ピクセルの色コンポーネントは、R(1)R(2)...R(n)、G(1)G(2)...G(n)、B(1)B(2)...B(n)、A(1)A(2)...A(n)の形に再配列される。この再配列を作り出するための効率的なアルゴリズムは、1番目の128ビットの画像を4つの32ビットピクセルを備えるようにロードすることである。次に、1番目、5番目、9番目および13番目の8ビットセクションにRバッファを加え、2番目、6番目、10番目および14番目の8ビットセクションにGバッファを加え、3番目、7番目、11番目および15番目の8ビットセクションにBバッファを加える。次に、連続する128ビット画像ごとにそのプロセスを繰り返す。実施形態において、Aチャネルは平坦化されるわけでも後で使用されるわけでもなく、計算時間を節約して画像を圧縮するために廃棄される。
【0029】
動作206は、Rベクトル、Gベクトル、およびBベクトルのそれぞれを解凍して、8つのゼロのシーケンスを8ビットのベクトルの前にそれぞれ入れるようにすることを示している。ピクセルの各チャネルが8ビットを備える実施形態において、これは、2つの係数によってすべてのベクトルサイズが増加するだけでなく、2つの係数によって各ピクセルが占める有効空間(effective space)も増加する。RベクトルがR(0)R(1)...R(n)として表されて8つのゼロのストリングが0x00として表される場合、解凍ベクトルは、それらのゼロが各ピクセルの赤値の前に置かれて、0×00、R(0)、0x00、R(1)、...0x00、R(n)となる。
【0030】
動作208は、Coベクトルを、RベクトルからBベクトルを引いた値に等しくなるように設定することを示している。実施形態において、これは、128ビットのRベクトルおよびBベクトルに一度で動作される。これは、128ビットのデータに一度で動作できるプロセッサへの単一の命令を用いて、128ビットのRベクトルおよびBベクトルに一度でロードして、RベクトルからBベクトルを引くことを備える。ゼロを用いてベクトルが解凍された場合、各ベクトルの128ビットは、8ビットチャネル値を合計で64ビット、および8つのゼロから成る8グループを別に合計64ビット備える。ベクトルがゼロを介入して解凍されたので、オーバーフローの懸念がない。つまりどのオーバーフローもその8つのゼロのセットにあふれて次の数字まで行かない。例えば、圧縮値を0x11および0x1Fにしてそれらが和された場合、その結果は0x30となる。しかしながら、そのような値の解凍バージョンは0x0101および0x010Fであり、その結果は0x0210となる。右から8ビットのオーバーフローは、実データの左から8ビットになるのではなくゼロになる。この方法において同様のロジックを他の動作に適用し、特に動作210−214に適用する。
【0031】
動作210は、Yベクトルを、等差級数的に右に1回シフトしてBベクトルとCoベクトルとの和に等しくなるように設定して、次に、等差級数的に右に1回シフトしてCgベクトルと和されることを示している。擬似コードにおいて、この動作をY=B+(Co>>1)と表すことができる。実施形態において、単一のプロセッサ命令を用いてCoをシフトして、それを一時的な値に記録して、次に2番目の単一のプロセッサ命令を用いてYをBとその一時的な値との和に設定する。実施形態において、これは、128ビットの各ベクトルに一度で行われる。Coが0x1111 1111 1111 1101に等しく、それが右に1回シフトされたビットの場合、各ビットは右の場所に移動されて、右端のビットが廃棄されて、次に左端から2番目のビットがゼロ値を割り当てられる(左端のビットは、その数字が正の数か負の数かどうか示すのに使用されて、保存される)。こうして、0x1101 1111 1111 1110が作り出される。
【0032】
動作212は、Cgベクトルを、YベクトルからGベクトルを引いた値に等しくなるように設定することを示している。実施形態において、これは、128ビットの各ベクトルに一度で行われる。
【0033】
動作214は、Yベクトルを、等差級数的に右に1回シフトしてYベクトルをCgベクトルに加えた値に等しくなるように設定することを示している。実施形態において、これは、128ビットの各ベクトルに一度で行われる。擬似コードにおいて、この動作をY=Y+(Cg>>1)と表すことができる。
【0034】
128ビットのベクトルに一度で動作する実施形態において、その方法は、次に連続する128ビットの各ベクトルに対して、各ベクトルがすべてこのように操作されるまで動作208−214を繰り返す。これらの動作がすべての画像上で動作するようにループされた実施形態において、その命令は、各ループ内に2回表示される。これは、単一の動作を用いて、平坦化された128のベクトルがメモリ内にロードされる場合に有利である。1番目の64ビットが解凍されて、次に動作されて、次に付加的なメモリアクセスなしで2番目の64ビットを解凍して動作できる。すべての128ビットが動作される時、別のメモリアクセスが要求されてそのループが再度開始される。
【0035】
動作216は、Coベクトルを、Coベクトルを色損失レベルで割った値に等しくなるように設定し、次にクロムマスクに加えられることを示している。実施形態において、色損失レベルは、各16ビットピースのCoベクトルを右にシフトするために事前に決められたビット数であり(上記のように、値が符号化される場合に符号を保存する)、画像を圧縮する量に対応する。これによって、色情報の精度がいくらか低下する(最も重要でないビットが廃棄される)だけでなく、さらに多くのピクセルが同じ色値を有するので画像が最終的に圧縮され得る量も増加する(ランレングス符号化アルゴリズムの有効性が増加する)。同様に、クロムマスクは、クロム損失レベルによって16ビットごとをビット単位にして右にシフトされる128のセットを表す。クロムマスクレベルの和において、1番目のレベルの圧縮が行われる。
【0036】
動作218は、Cgベクトルを、Cgベクトルを色損失レベルで割った値に等しくなるように設定し、次にクロムマスクに加えられることを示している。実施形態において、色損失レベルは、各16ビットピースのCoベクトルを右にシフトするために事前に決められたビット数であり(上記のように、値が符号化される場合に符号を保存する)。これによって、色情報の精度がいくらか低下する(最も重要でないビットが廃棄される)だけでなく、さらに多くのピクセルが同じ色値を有するので画像が最終的に圧縮され得る量も増加する(ランレングス符号化アルゴリズムの有効性が増加する)。同様に、クロムマスクは、クロム損失レベルによって16ビットごとをビット単位にして右にシフトされる128のセットを表す。クロムマスクレベルの和において、1番目のレベルの圧縮が行われる。実施形態において、クロムマスクは2進数列を備え、それらは、ピクセルの赤値のビット数の2倍に対応するビットグループ内の色損失レベルによって右にシフトされたビットを、プロセッサが同時に等差級数的に動作できるビット数に等しい。
【0037】
動作220は、CoおよびCgベクトルをサブサンプリングする任意のステップを示している。これを、例えば、いくつかの隣接ピクセルの色値を平均化して、その平均値を各ピクセルの色値に割り当てることによって完了できる。これによって、多くの値が反復されるので、圧縮アルゴリズムが出力画像となる記憶空間をさらに削減することが可能になるであろう。
図3の考察においてこの動作の実施形態のさらなる詳細が与えられる。
【0038】
動作222は、Yベクトルをランレングス符号化することを示している。実施形態において、Yベクトルは、他の2つのベクトルが動作216および218で行われるように圧縮される。これは、人間の目がYベクトルで表される輝度に最も敏感であるので、この情報を保存する際、人間は他の2つのチャネルに対するロッシー圧縮があまり目立たないと思うであろう。ランレングス符号化は、同じデータ値が単回に分かれて連続したデータ値を、その回数によって表されるデータ値の数をカウントしながら記憶することによってベクトルを圧縮することを備えるロスレス圧縮スキームである。例えば、文字ストリングAAAAAAABBBBAAAAAがあるとして、このストリングのランレングスの符号化バージョンを(A7)(B3)(A5)と表現できる。実施形態において、このランレングス符号化は、レンペルジフ(LZ)アルゴリズムに従って行われる。LZアルゴリズムは、典型的には、圧縮されるオブジェクトとLZアルゴリズムによって保持されるデータ構造(しばしば辞書と呼ばれる)内に含まれるストリングのセットとの間で一致を検索することによって動作する。LZアルゴリズムが一致を見つける時、それは、データ構造内の一致する位置の参照と一致自体とを置き換える。実施形態において、他のランレングス符号化技術を使用して、反復実行を探して、そしてその反復実行を、反復される連長およびバイトパターンを表示するコードと置き換える順方向検索を行うことができる。実施形態において、二次元ランレングス符号化技術は、圧縮効率を高めるのに使用される。これは、ランレングス符号化をさらに容易にすることができる垂直反復が存在するゼロの「垂直」ストリップを実現するために、現在のピクセル行と以前のピクセル行との排他的論理和(XOR‘ing)によって実現される。
【0039】
動作224は、Coベクトルをランレングス符号化することを示している。この符号化形態は、ごくわずかの異なるタイプの色を使用する画像上で最も効果がある(色調または色相の非常にわずかな変化であってもランレングス符号化の付加的な記憶空間を要求する)ので、その技術には、上記のベクトルに適用されるクロマ損失レベルが有効である。
【0040】
動作226は、Cgベクトルをランレングス符号化することを示している。これを、動作222または224と同様にして行うことができる。
【0041】
動作228は、出力画像の記憶を示しており、その出力画像はYベクトル、CoベクトルおよびCgベクトルを備え、その出力画像はそのソース画像に対応する。実施形態において、これは、YCoCg画像を非平坦化することを備える。実施形態において、記憶は、RAMなどのメモリに記憶して、次にクライアントによって使用されるリモートデスクトッププロトコル(RDP)に従ってコンピュータネットワークに画像を伝送することを備える。
【0042】
図3は、
図2の動作可能なプロシージャによって作り出されるような出力画像をサブサンプリングするための動作可能なプロシージャを示している。それを
図2の動作220の実施形態とすることができる。
【0043】
動作302は、出力画像を少なくとも1クアッド(quad)にセグメント化するステップを示しており、クアッドは、クアッド内の各ピクセルが出力画像の列をそのクアッド内のもう1つのピクセルと共有およびクアッド内の各ピクセルが出力画像の行をそのクアッド内のもう1つのピクセルと共有できるように4ピクセルを備え、各クワッドは、上部行(top row)および下部行(bottom row)を有し、しかもピクセルは最大でも1クワッドしか対応しない。この実施形態において、画像をサブサンプリングすることによってさらなる圧縮が生成され、CoおよびCgベクトルをランレングス符号化する前に、圧縮を高めるための画像の前処理を行うことできる。このような動作は、(画像忠実度の損失において)ピクセルによって表される色値の均一性を高めるので、ランレングス符号化を使用した圧縮の増加が可能になる。
【0044】
動作304は、各クワッドの各行を16ビット値に解凍して、各行をゼロで配置するステップを示している。ピクセルの各チャネルが8ビットを備える実施形態において、これは、2つの係数によってすべてのベクトルサイズが増加するだけでなく、2つの係数によって各ピクセルが占める有効空間も増加する。RベクトルがR(0)R(1)...R(n)として表されて8つのゼロのストリングが0x00として表される場合、解凍ベクトルは、それらのゼロが各ピクセルの赤値の前に置かれて、0x00、R(0)、0x00、R(1)、...0x00、R(n)となる。
【0045】
動作306は、各クワッドの上部行と下部行とを和して合わされた行を作り出すステップを示しており、そこでは各行内の各ピクセルが飽和値を有していて、上部行内のピクセルと下部行内のピクセルとの和が飽和値を越える時、上部行内のピクセルと下部行内のピクセルとの和をその飽和値に設定する。つまり、ピクセルの各チャネルが8ビットの情報を備えていて、そのチャネルの値が8ビットの符号なし整数として表されている場合、そのチャネルが有し得る最大値は、2^8−1すなわち255である。この255は、それより大きい値を記憶できないので、この例での飽和値である。2つの数字の和が255を超えるようでも、その和は255に設定される。つまり、100と150との和は、合わせて250の値を有する行になるが、通常350になるであろう100と250との和は、飽和値に限定され、その合わされた行は255の値を有する。この動作は、動作234−238と同様に画像のサブサンプリング部を備えることができる。
【0046】
動作308は、合わされた各クワッドの行を、合わされたそのクワッドの行のワードシャッフルバージョン(word−shuffled version)と和すステップを示している。行を左から右にピクセル値0、1、2、3として表し得る場合、最初の2つの値が入れ替わることおよび最後の2つの値が入れ替わることによって、行1、0、3、2が作り出される。これは、次に、元行(original row)に加えられて、0+1、1+0、2+3、3+2の値を作り出す。そこで、最初の2つの値が互いに等しいおよび2番目の値が互いに等しいので、それらを冗長として無視できる。
【0047】
動作310は、和して合わされた各クワッドの行を4で割るステップを示している。実施形態において、これは、2つの行の場所を等差級数的に右にシフトすることによって完了する。実施形態において、これは、128ビットの各ベクトルに一度で行われ、そのシフトは、上記の等差級数的シフティングの考察と同様に、128ビットストリングの4つの32ビット部で個々に発生する。4で割ることによって、クワッドの平均値が決定される。平均値を使用する際、ロッシー圧縮が実現される。4つの係数によって精度が低下するが、記憶される1つの値がクワッド内の4つのすべてのピクセルに対応するので、以前と比較してわずか4分の1の値を記憶すればよい。実施形態において、現在のクワッド内の冗長値は廃棄される。
【0048】
動作312は、和して合わされた各クワッドの行を再圧縮するステップを示している。
実施形態において、これは、解凍動作と同類(sibling)である。つまり、その解凍動作中に導入された8つのゼロのグループを廃棄する。
【0049】
<サンプルコード>
以下は、ハイレベルなC言語プログラミングのシンタックスにおけるサンプル擬似コードを備え、ベクトルプロセッサ上で実行される時、
図2の詳細な説明で説明したのと同様に本開示の実施形態の方法において、ソース画像“srcImage”に動作する。
【0050】
ULONG
NSTestCompress(
NSBitmap& srcImage,
PBYTE pOutputBuf,
ULONG cbMaxOutbufSize,
PBYTE pYBuffer,
PBYTE pCoBuffer,
PBYTE pCgBuffer,
ULONG cbPlaneOutputSize,
PBYTE pWorkBuf,
ULONG cbWorkBuf)
{
BOOL bSubSample = NS_SUBSAMPLE;
// We operate 4 pixels at a time
//
// P0 = R0G0B0A0
// P1 = R1G1B1A1
// P2 = R2G2B2A2
// P3 = R3G3B3A3
//
// First we planarize as follows using CPU
// Rn = R0R1R2R3
// Gn = G0G1G2G3
// Gn
//
//
//
// 16-byte align the output buffer
pYBuffer = (PBYTE)(XROUND_UP_16((ULONG)pYBuffer));
pCoBuffer = (PBYTE)(XROUND_UP_16((ULONG)pCoBuffer));
pCgBuffer = (PBYTE)(XROUND_UP_16((ULONG)pCgBuffer));
PBYTE pYBufferOrig = pYBuffer;
PBYTE pCoBufferOrig = pCoBuffer;
PBYTE pCgBufferOrig = pCgBuffer;
//
// 1) Prep the data by splitting planes
//
PBYTE pRbuffer, pGbuffer, pBbuffer;
//
// 16-byte align channels for SSE perf
//
ULONG cbColorChannelSpace = XROUND_UP_16(srcImage._height * srcImage._width);
if (cbColorChannelSpace * 3 > cbWorkBuf) {
return 0;
}
pRbuffer = pWorkBuf;
pGbuffer = pRbuffer + cbColorChannelSpace;
pBbuffer = pGbuffer + cbColorChannelSpace;
PBYTE pSrcPixel;
PBYTE pEndPixel;
ULONG* pRBufferDWORD = (ULONG*)XROUND_UP_16((ULONG)pRbuffer);
ULONG* pGBufferDWORD = (ULONG*)XROUND_UP_16((ULONG)pGbuffer);
ULONG* pBBufferDWORD = (ULONG*)XROUND_UP_16((ULONG)pBbuffer);
//
// 1) PLANARIZE - EFFICIENT
//
pSrcPixel = srcImage._pImgBits;
pEndPixel = pSrcPixel + srcImage._height* srcImage._stride;
while (pSrcPixel < pEndPixel) {
*pRBufferDWORD++ = X_MAKE_DWORD(pSrcPixel[0], pSrcPixel[4], pSrcPixel[8], pSrcPixel[12]);
*pGBufferDWORD++ = X_MAKE_DWORD(pSrcPixel[1+0], pSrcPixel[1+4], pSrcPixel[1+8], pSrcPixel[1+12]);
*pBBufferDWORD++ = X_MAKE_DWORD(pSrcPixel[2+0], pSrcPixel[2+4], pSrcPixel[2+8], pSrcPixel[2+12]);
【0051】
pSrcPixel+=16;
}
//
// 2 Compute Y Coefficients
//
__m128i xmmZero = _mm_setzero_si128();
__m128i xmmRvect, xmmGvect, xmmBvect;
__m128i xmmYFirstQWORD, xmmCoFirstQWORD;
PBYTE pRbufferReader = pRbuffer;
PBYTE pGbufferReader = pGbuffer;
PBYTE pBbufferReader = pBbuffer;
PBYTE pBbufferReaderEnd = (pRbuffer + cbColorChannelSpace);
__m128i xmm1, xmm2, xmm3, xmmCo, xmmY, xmmCg;
__m128i xmmCo2, xmmY2, xmmCg2;
__m128i xmmChromaMask = _mm_set_epi16(0x1ff >> X_COLOR_LOSS_LEVEL,
0x1ff >> X_COLOR_LOSS_LEVEL,
0x1ff >> X_COLOR_LOSS_LEVEL,
0x1ff >> X_COLOR_LOSS_LEVEL,
0x1ff >> X_COLOR_LOSS_LEVEL,
0x1ff >> X_COLOR_LOSS_LEVEL,
0x1ff >> X_COLOR_LOSS_LEVEL,
0x1ff >> X_COLOR_LOSS_LEVEL);
while (pRbufferReader < pBbufferReaderEnd) {
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// First 64-bits in parallel
//
//
// Read color vectors
//
xmmRvect = _mm_loadl_epi64((__m128i*)pRbufferReader);
xmmGvect = _mm_loadl_epi64((__m128i*)pGbufferReader);
xmmBvect = _mm_loadl_epi64((__m128i*)pBbufferReader);
pRbufferReader += 8;
pGbufferReader += 8;
pBbufferReader += 8;
// unpack to R 0 G 0 B 0 (16 bits per channel to make math per
//16 bit possible)
xmmRvect = _mm_unpacklo_epi8(xmmRvect, xmmZero);
xmmGvect = _mm_unpacklo_epi8(xmmGvect, xmmZero);
xmmBvect = _mm_unpacklo_epi8(xmmBvect, xmmZero); i
// NOTE 3
// co = r - b;
// y = b + (co >> 1);
// cg = g - y;
// y += (cg >> 1);
xmmCo = _mm_subs_epi16(xmmRvect, xmmBvect);// co = R - B
xmm1 = _mm_srai_epi16(xmmCo, 1); // co >> 1
xmmY = _mm_adds_epi16(xmmBvect, xmm1); // y = b + co >> 1
xmmCg = _mm_subs_epi16(xmmGvect, xmmY); // cg = g - y
xmm1 = _mm_srai_epi16(xmmCg, 1); // cg >> 1
xmmY = _mm_adds_epi16(xmmY, xmm1); // y += cg >> 1
// Now do masks on Co and Cg
xmmCo = _mm_srai_epi16(xmmCo, X_COLOR_LOSS_LEVEL);
xmmCo = _mm_and_si128(xmmCo, xmmChromaMask);
xmmCg = _mm_srai_epi16(xmmCg, X_COLOR_LOSS_LEVEL);
xmmCg = _mm_and_si128(xmmCg, xmmChromaMask);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Second 64-bits
//
//
【0052】
// Read color vectors
//
xmmRvect = _mm_loadl_epi64((__m128i*)pRbufferReader);
xmmGvect = _mm_loadl_epi64((__m128i*)pGbufferReader);
xmmBvect = _mm_loadl_epi64((__m128i*)pBbufferReader);
pRbufferReader += 8;
pGbufferReader += 8;
pBbufferReader += 8;
// unpack to R 0 G 0 B 0 (16 bits per channel to make math per
//16 bit possible)
xmmRvect = _mm_unpacklo_epi8(xmmRvect, xmmZero);
xmmGvect = _mm_unpacklo_epi8(xmmGvect, xmmZero);
xmmBvect = _mm_unpacklo_epi8(xmmBvect, xmmZero);
//
// co = r - b;
// y = b + (co >> 1);
// cg = g - y;
// y += (cg >> 1);
xmmCo2 = _mm_subs_epi16(xmmRvect, xmmBvect);// co = R - B
xmm1 = _mm_srai_epi16(xmmCo2, 1); // co >> 1
xmmY2 = _mm_adds_epi16(xmmBvect, xmm1); // y = b + co >> 1
xmmCg2 = _mm_subs_epi16(xmmGvect, xmmY2); // cg = g - y
xmm1 = _mm_srai_epi16(xmmCg2, 1); // cg >> 1
xmmY2 = _mm_adds_epi16(xmmY2, xmm1); // y += cg >> 1
// Now do masks on Co and Cg
xmmCo2 = _mm_srai_epi16(xmmCo2, X_COLOR_LOSS_LEVEL);
xmmCo2 = _mm_and_si128(xmmCo2, xmmChromaMask);
xmmCg2 = _mm_srai_epi16(xmmCg2, X_COLOR_LOSS_LEVEL);
xmmCg2 = _mm_and_si128(xmmCg2, xmmChromaMask);
//
// Now do storage
//
// Y component - pack into 16-bytes
xmmY = _mm_packs_epi16(xmmY, xmmY2);
_mm_store_si128((__m128i*)pYBuffer, xmmY); //stores in one shot
pYBuffer += 16;
// Co component - pack into 16-bytes
xmmCo = _mm_packs_epi16(xmmCo, xmmCo2);
_mm_store_si128((__m128i*)pCoBuffer, xmmCo);
pCoBuffer += 16;
// Cg component - pack into 16-bytes
xmmCg = _mm_packs_epi16(xmmCg, xmmCg2);
_mm_store_si128((__m128i*)pCgBuffer, xmmCg);
pCgBuffer += 16;
}
//
// Now do the ACRUSH magic on each channel!;
//
ULONG retVal;
if (!g_pACContext) {
g_cbACContextSize = RDPCompress_GetContextSize(PACKET_COMPR_TYPE_ACRUSH);
g_pACContext = malloc(g_cbACContextSize);
RDPCompress_InitSendContext(g_pACContext, g_cbACContextSize, PACKET_COMPR_TYPE_ACRUSH);
}
ULONG cbCompressedSize;
ULONG cbOrigSize;
//
// Do Y Channel
//
cbCompressedSize = cbColorChannelSpace;
ULONG cbOutSizeTotal = 0;
PBYTE pCurWriteOutput = pOutputBuf;
//
// ~~~~~~~~~~~~~~~~~~ Y component ~~~~~~~~~~~~~
//
【0053】
retVal = XRDPCompress(PACKET_COMPR_TYPE_ACRUSH,
pYBufferOrig,
pCurWriteOutput,
&cbCompressedSize,
g_pACContext);
/// printf("Y: run=%d compr=%d\n", cbRunLength, cbCompressedSize);
if (retVal & PACKET_COMPRESSED) {
cbOutSizeTotal += cbCompressedSize;
}
else {
memcpy(pCurWriteOutput, pYBufferOrig, cbColorChannelSpace);
cbOutSizeTotal += cbColorChannelSpace;
}
pCurWriteOutput += cbOutSizeTotal;
//
// ~~~~~~~~~~~~~~~~~~ Co component ~~~~~~~~~~~~~
//
//
// Downsample CO
//
if (bSubSample) {
ULONG cbSubSampleSize;
cbSubSampleSize = NSSubSample2xColorChannelSSE(pCoBufferOrig, cbColorChannelSpace, srcImage._width, srcImage._height,
pWorkBuf, cbWorkBuf);
pCoBufferOrig = pWorkBuf;
cbCompressedSize = cbSubSampleSize;
}
else {
cbCompressedSize = cbColorChannelSpace;
}
retVal = XRDPCompress(PACKET_COMPR_TYPE_ACRUSH,
pCoBufferOrig,
pCurWriteOutput,
&cbCompressedSize,
g_pACContext);
if (retVal & PACKET_COMPRESSED) {
cbOutSizeTotal += cbCompressedSize;
}
else {
memcpy(pCurWriteOutput, pCoBufferOrig, cbColorChannelSpace);
cbOutSizeTotal += cbColorChannelSpace;
}
pCurWriteOutput += cbCompressedSize;
//
// ~~~~~~~~~~~~~~~~~~ Cg component ~~~~~~~~~~~~~ //exactly same as Co
//
// Downsample CO
//
if (bSubSample) {
ULONG cbSubSampleSize;
cbSubSampleSize = NSSubSample2xColorChannelSSE(pCgBufferOrig, cbColorChannelSpace, srcImage._width, srcImage._height,
pWorkBuf, cbWorkBuf);
pCgBufferOrig = pWorkBuf;
cbCompressedSize = cbSubSampleSize;
}
else {
cbCompressedSize = cbColorChannelSpace;
【0054】
}
retVal = XRDPCompress(PACKET_COMPR_TYPE_ACRUSH,
pCgBufferOrig,
pCurWriteOutput,
&cbCompressedSize,
g_pACContext);
if (retVal & PACKET_COMPRESSED) {
cbOutSizeTotal += cbCompressedSize;
}
else {
memcpy(pCurWriteOutput, pCgBufferOrig, cbColorChannelSpace);
cbOutSizeTotal += cbColorChannelSpace;
}
pCurWriteOutput += cbCompressedSize;
return cbOutSizeTotal;
}
【0055】
以下は、ハイレベルなC言語プログラミングのシンタックスにおけるサンプル擬似コードを備え、ベクトルプロセッサ上で実行される時、
図3の詳細な説明で説明したのと同様に本開示の実施形態の方法において、パラメータNSSubSample2xColorChannelSSE()によって定義された画像に動作する。
【0056】
ULONG
NSSubSample2xColorChannelSSE(
PBYTE pSrcBytes,
ULONG cbLength,
ULONG width,
ULONG height,
PBYTE pOutputBytes,
ULONG cbMaxOutputLen
)
{
PBYTE pEndData = pSrcBytes + width*height;
__m128i xmmZero = _mm_setzero_si128();
ULONG* pOutputWriter = (ULONG*)pOutputBytes;
//
// Fix fix no uniform row
//
for (ULONG i=0; i<height-1; i++) {
PBYTE pCurrentRow = pSrcBytes + width * i;
PBYTE pRowEnd = pCurrentRow + width;
__m128i srcDataRow0;
__m128i xmm1;
__m128i srcDataRow1;
while (pCurrentRow < pRowEnd) {
srcDataRow0 = _mm_loadl_epi64((__m128i*)pCurrentRow);
srcDataRow1 = _mm_loadl_epi64((__m128i*)(pCurrentRow+width));
pCurrentRow += 8;
//
// Unpack to 16-bit values
//
srcDataRow0 = _mm_unpacklo_epi8(srcDataRow0, xmmZero);
srcDataRow1 = _mm_unpacklo_epi8(srcDataRow1, xmmZero);
//
// Add with saturate row1+row2
//
srcDataRow0 = _mm_adds_epi16(srcDataRow0, srcDataRow1);
//
//make a copy shuffled to swap each WORD
//
【0057】
xmm1 = _mm_shufflehi_epi16(srcDataRow0, _MM_SHUFFLE(2,3,0,1));
xmm1 = _mm_shufflelo_epi16(srcDataRow0, _MM_SHUFFLE(2,3,0,1));
//
// Now add the alternating cols
//
xmm1 = _mm_adds_epi16(xmm1, srcDataRow0);
xmm1 = _mm_srai_epi16(xmm1, 2);
xmm1 = _mm_shufflehi_epi16(xmm1, _MM_SHUFFLE(3,1,2,0));
xmm1 = _mm_shufflelo_epi16(xmm1, _MM_SHUFFLE(3,1,2,0));
// bring together the unique values in the 2-LOWDWORDS
xmm1 = _mm_shuffle_epi32(xmm1, _MM_SHUFFLE(3,1,2,0));
//
// We now have
// (P00+P01+P10+P11) (P00+P01+P10+P11)
// (P02+P03+P12+P13)(P02+P03+P12+P13)
// net every other 16-bit value is redundant - pack away now
//
xmm1 = _mm_packs_epi16(xmm1, xmmZero);
// low 4 bytes are the averages we want
*pOutputWriter++ = *((ULONG*)&xmm1);
}
}
return cbLength / 4;
}