⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mchannel.c

📁 c++ Builder中网络图象渐进传输实例
💻 C
字号:
// --------------- MULTI-CHANNEL ROUTINES ---------------
// wavelet image compression
// channel balancing & quality enforcement
// (c) 2001-2002 Daniel Vollmer (maven@maven.de)

/* 	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
*/

#include "wavelet.h"
#include "mchannel.h"


// colour-space conversion (using 16.16 fixed point)
// this is the same transform as used in JPEG, and the results still need
// to be rounded and shifted / divided

#define RGB_Y(r, g, b) ((r) * 19595 + (g) * 38470 + (b) * 7471)
#define RGB_Cb(r, g, b) ((r) * -11059 + (g) * -21709 + (b) * 32768)
#define RGB_Cr(r, g, b) ((r) * 32768 + (g) * -27439 + (b) * -5329)

// the results of these need to be clamped to the range [0..255] after rounding
// and shifting
#define YCbCr_R(y, cb, cr) (/*(y) * 65536 + (cb) * 0 +*/ (cr) * 91881)
#define YCbCr_G(y, cb, cr) (/*(y) * 65536 +*/ (cb) * -22554 + (cr) * -46802)
#define YCbCr_B(y, cb, cr) (/*(y) * 65536 +*/ (cb) * 116130 /*+ (cr) * 0*/)

//----------------------------------------------------------------------------
// wv_rgb_to_ycbcr	converts an array of pixels
//				(given as seperate bitplanes) from RGB into YCbCr
//				returns the number of pixels converted
// Num			numbers of consecutive pixels to be converted
// R, G, B		pointers to the red, green and blue arrays, respectively (R->Y, G->Cb, B->Cr)
//----------------------------------------------------------------------------
WAVELET_DLL_API int WAVELET_DLL_CC wv_rgb_to_ycbcr(const int Num, wv_pel* R, wv_pel* G, wv_pel* B)
{
	if (Num > 0 && R && G && B)
	{
		int i;

		for (i = 0; i < Num; i++)
		{
			int rr = R[i], gg = G[i], bb = B[i];

			R[i] = (wv_pel)((RGB_Y(rr, gg, bb) + 32768) >> 16); // Y
			G[i] = (wv_pel)(((RGB_Cb(rr, gg, bb) + 32767) >> 16)); // Cb
			B[i] = (wv_pel)(((RGB_Cr(rr, gg, bb) + 32767) >> 16)); // Cr
		}
		return Num;
	}
	return 0;
}


//----------------------------------------------------------------------------
// wv_ycbcr_to_rgb	converts an array of pixels
//				(given as seperate bitplanes) from YCbCr into RGB
//				returns the number of pixels converted
// Num			numbers of consecutive pixels to be converted
// Y, Cb, Cr	pointers to the Y, Cb, and Cr arrays, respectively (Y->R, Cb->G, Cr->B)
//----------------------------------------------------------------------------
WAVELET_DLL_API int WAVELET_DLL_CC wv_ycbcr_to_rgb(const int Num, wv_pel* Y, wv_pel* Cb, wv_pel* Cr)
{
	if (Num > 0 && Y && Cb && Cr)
	{
		int i;

		for (i = 0; i < Num; i++)
		{
			int yy = Y[i], cb = Cb[i], cr = Cr[i];
			
			Y[i] = yy + ((YCbCr_R(yy, cb, cr) + 32768) >> 16); Y[i] = min(255, max(0, Y[i])); // R
			Cb[i] = yy + ((YCbCr_G(yy, cb, cr) + 32768) >> 16); Cb[i] = min(255, max(0, Cb[i])); // G
			Cr[i] = yy + ((YCbCr_B(yy, cb, cr) + 32768) >> 16); Cr[i] = min(255, max(0, Cr[i])); // B
		}
		return Num;
	}
	return 0;
}


//----------------------------------------------------------------------------
// wv_init_multi_channels	tries to find the matching settings for
//				a number of channels (i.e. satisfy all the constraints given)
//				returns the bits needed (never larger than MaxBits),
//				0 on failure to satisfy contraints
// MaxBits		number of bits to be used by all the channels,
//				or 0 for quality based encoding
// Threshold	how closely it tries to equalise quality (of the channels),
//				should be inbetween 0.0f..1.0f for good results, use 0.0f
//				if you don't mind waiting slightly longer...
// NumChannels	# of channels given in Channels to be compressed
// Channels		is the array of channel-parameters with NumChannels entries
//				(need a valid t_wv_cchannel and max_mse),
//				when encoding for quality each channel's max_mse gives the
//				maximum target error,
//				when encoding for size each channel's max_mse gives a
//				a target error relative to the other channels
// Sets			array with NumChannels entries where the best settings are
//				stored (on success). These have to be freed by the calling
//				application using wv_done_channel_settings.
//----------------------------------------------------------------------------
WAVELET_DLL_API int WAVELET_DLL_CC wv_init_multi_channels(const int MaxBits, const float Threshold, const int NumChannels, t_wv_mchannel_params* Channels, t_wv_csettings** Sets)
{
	int bits = 0;

	if (NumChannels > 0 && Channels && Sets)
	{
		int i;

		for (i = 0; i < NumChannels; i++)
			Sets[i] = NULL;
		if (MaxBits <= 0)
		{ // simply enforce mse constraints
			for (i = 0; i < NumChannels; i++)
			{
				bits = wv_init_channel_settings(Channels[i].cc, 0, Channels[i].max_mse, &Sets[i]);
				if (bits <= 0)
					break;
			}
		}
		else
		{ // balance the channels so that MSEs are about equal (including max_mse interpreted as delta_mse)
			int num_iter = 0, adjustment;
			int omin_idx = -1, omax_idx = -1;
			t_wv_csettings* lsets[wv_MAX_CHANNELS];
			float closest_match = NumChannels * 65536.0f;

			for (i = 0; i < NumChannels; i++)
			{
				Channels[i].bits_unused = Channels[i].old_bits = 0;
				Sets[i] = NULL;
				lsets[i] = NULL;
			}
		
			// distribute the bits equally as inital state
			adjustment = 0;
			for (i = 1; i < NumChannels; i++)
			{
				Channels[i].bits_alloced = MaxBits / NumChannels;
				adjustment += Channels[i].bits_alloced;
			}
			Channels[0].bits_alloced = MaxBits - adjustment; // gets all the bits left over
			adjustment = 1;
			
			do
			{
				float bmin_mse = 65536.0f, bmax_mse = -1.0f;
				float avg_mse = 0.0f;
				int bmin_idx = -1, bmax_idx = -1;
				int bits_available;

				for (i = 0; i < NumChannels; i++)
				{
					if (lsets[i] && Channels[i].bits_alloced != Channels[i].old_bits)
					{
						wv_done_channel_settings(lsets[i]);
						lsets[i] = NULL;
					}
					if (!lsets[i])
						bits = wv_init_channel_settings(Channels[i].cc, Channels[i].bits_alloced, 65536.0f, &lsets[i]);
					else
						bits = lsets[i]->num_bits;
					if (bits > 0 && lsets[i])
					{
//						fprintf(f, "%i bits_a: %i bits_u: %i error: %f\n", i, Channels[i].bits_alloced, lsets[i]->num_bits, lsets[i]->emse);
						Channels[i].old_bits = bits; // as we are going to redistribute the unused ones							
						Channels[i].bits_unused = Channels[i].bits_alloced - bits;
						// find the best and the worst channel (including relative error adjustments)
						if (lsets[i]->emse - Channels[i].max_mse <= bmin_mse)
						{
							bmin_mse = lsets[i]->emse - Channels[i].max_mse;
							bmin_idx = i;
						}
						if (lsets[i]->emse - Channels[i].max_mse >= bmax_mse)
						{
							bmax_mse = lsets[i]->emse - Channels[i].max_mse;
							bmax_idx = i;
						}
						avg_mse += lsets[i]->emse;
					}
					else
						break;
				}
						
				if (i != NumChannels || bmin_idx == -1 || bmax_idx == -1)
				{ // uh-oh, shouldn't happen
					bits = 0;
					break; // bits == 0 -> abort
				}
/*				// equalise difference between best & worst mse
				if (bmax_mse - bmin_mse <= closest_match)
				{ // this is better than our best-one so far, so keep it
					for (i = 0; i < NumChannels; i++)
					{
						Sets[i] = lsets[i]; // copy the set
						lsets[i] = NULL; // and don't let it be deleted
					}
					closest_match = bmax_mse - bmin_mse;
				}*/
				if (avg_mse <= closest_match)
				{ // this is better than our best-one so far, so keep it
					for (i = 0; i < NumChannels; i++)
					{
						Sets[i] = lsets[i]; // copy the set
						lsets[i] = NULL; // and don't let it be deleted
					}
					closest_match = avg_mse;
				}
				if ((bmin_idx == bmax_idx) || (bmax_mse - bmin_mse <= Threshold))
					break; // balanced or only one channel

				if (bmin_idx == omax_idx && bmax_idx == omin_idx)
				{
					adjustment++;
					if (adjustment > 16)
						break; // only flipping between two channels
				}

				// redistribute bits							
				bits_available = 0; // add up all the unused bits
				for (i = 0; i < NumChannels; i++)
					if (i != bmin_idx && i != bmax_idx)
					{
						bits_available += Channels[i].bits_unused;
						Channels[i].bits_alloced -= Channels[i].bits_unused;
					}
				
				// redistribute the unused bits, plus the one from the best & worst channel among them
				bits_available += Channels[bmin_idx].bits_alloced + Channels[bmax_idx].bits_alloced;

				Channels[bmin_idx].bits_alloced = (Channels[bmin_idx].bits_alloced * adjustment) / (adjustment + 1);
				Channels[bmax_idx].bits_alloced = bits_available - Channels[bmin_idx].bits_alloced; // gets the rest

				omin_idx = bmin_idx;
				omax_idx = bmax_idx;

				num_iter++;
			} while (num_iter < 256);

			// free the settings (we've copied the best ones to Sets)
			for (i = 0; i < NumChannels; i++)
				if (lsets[i] != NULL)
					wv_done_channel_settings(lsets[i]);
		}
		
		// recompute the final number of bits used
		bits = 0;
		for (i = 0; i < NumChannels; i++)
			if (Sets[i])
				bits += Sets[i]->num_bits;
	}
	return bits;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -