主頁 >  其他 > 實驗五-JPEG原理分析及JPEG解碼器的除錯

實驗五-JPEG原理分析及JPEG解碼器的除錯

2021-06-10 09:57:48 其他

JPEG原理分析及JPEG解碼器的除錯

一、實驗簡介

JPEG( Joint Photographic Experts Group)是用于連續色調靜態影像壓縮的一種標準,檔案后綴名為.jpg或.jpeg,是最常用的影像檔案格式,
主要采用預測編碼(DPCM)、離散余弦變換(DCT)以及熵編碼的聯合編碼方式,以去除冗余的影像和彩色資料,屬于有損壓縮格式,
所謂有損壓縮,就是把原始資料中不重要的部分去掉,以便可以用更小的體積保存,

1、JPEG格式分析

具體對照分析方法參見PNG格式分析

(1)SOI

SOI ,Start of Image,影像開始,標記代碼2位元組,固定值0xFFD8
在這里插入圖片描述

(2)APP0

APP0,Application,應用程式保留標記0
在這里插入圖片描述
標記代碼 2位元組 FF E0
資料長度 2位元組 00 10
識別符號 5位元組 4A 46 49 46 00 ,即字串JFIF0
版本號 2位元組 01 01
X和Y的密度單位 1位元組 00-無單位
X方向像素密度 2位元組 00
Y方向像素密度 2位元組 01
縮略圖水平像素數目 1位元組 00
縮略圖垂直像素數目 1位元組 01

(3)DQT

DQT,Define Quantization Table,定義量化表
在這里插入圖片描述
標記代碼 2位元組 FF DB
資料長度 2位元組 00 43
在這里插入圖片描述

(4)SOF0

SOF0,Start of Frame,幀影像開始
在這里插入圖片描述

在這里插入圖片描述

(5)DHT

DHT,Define Huffman Table,定義哈夫曼表
在這里插入圖片描述
在這里插入圖片描述

(6)SOS

SOS,Start of Scan,掃描開始 12位元組
在這里插入圖片描述
在這里插入圖片描述

(7)EOI

EOI,End of Image,影像結束 ,標記代碼2位元組 固定值0xFFD9
在這里插入圖片描述

2、JPEG編碼原理

在這里插入圖片描述
JPEG壓縮編碼演算法的主要計算步驟如下:

(1) level offset

  • 將輸入圖片做一個零偏置電平下移,將原數值從無符號數轉換為有符號數,將值域往下做搬移,從而提高編碼效率,
  • 對于n=8,即將0~255的值域,通過減去128轉換為值域在-128~127之間的值

(2) 8*8 DCT

  • 將原始影像分為8*8的小塊, 對于圖片寬高不為8的倍數的圖片,進行邊緣填充處理,
  • 對每個8x8塊的每行進行變換,然后每列進行變換,得到的是一個8x8的變換系數矩陣,其中(0,0)位置的元素就是直流分量,矩陣中的其他元素根據其位置表示不同頻率的交流分量,

DCT(離散余弦變換)具有很強的"能量集中"特性,大多數的自然信號(包括聲音和影像)的能量都集中在DCT變換后的低頻部分,當信號具有接近馬爾科夫程序(Markov
processes)的統計特性時,離散余弦變換的去相關性接近于K-L變換(Karhunen-Loève
變換–它具有最優的去相關性)的性能,從而提高編碼效率

(3) 量化(quantization),

  • 量化就是用像素值÷量化表對應值所得的結果,
  • 量化表左上角的值較小,右上角的值較大,這樣就起到了保持低頻分量,抑制高頻分量的目的,由于人眼對低頻分量的敏感程度遠高于高頻分量,因此我們需要對低頻分量細量化,對高頻部分粗量化,通過量化可以達到通低頻減高頻的效果

在這里插入圖片描述
左邊那個量化表,最右下角的高頻÷16,這樣原先DCT后[-127,127]的范圍就變成了[-7,7],固然減少了碼字(從8位減至4位),

  • JPEG使用的顏色是YUV格式,我們提到過,Y分量代表了亮度資訊,UV分量代表了色差資訊,由于人對亮度的敏感程度遠高于色度,我們可以對Y采用細量化,對UV采用粗量化,從而進一步提高壓縮比,所以量化表通常有兩張,一張是針對Y的;一張是針對UV的,

(4) 編碼

編碼資訊分兩類,一類是使用差分脈沖編碼調制(DPCM)對直流系數(DC)進行編碼,一類是使用行程長度編碼(RLE)對交流系數(AC)進行編碼,

  • 使用差分脈沖編碼調制(DPCM)對直流系數(DC)進行編碼
    每個8 * 8格子F中的[0,0]位置上元素,代表8 * 8個子塊的平均值,JPEG中對F[0,0]單獨編碼,由于兩個相鄰的8×8子塊的DC系數相差很小,具有冗余,所以對它們采用差分編碼DPCM,可以提高壓縮比,也就是說對相鄰的子塊DC系數的差值進行編碼,
  • 使用行程長度編碼(RLE)對交流系數(AC)進行編碼
    另一類是8×8塊的其它63個子塊,即交流(AC)系數,采用行程編碼(游程編碼Run-length encode,RLE),為了保證低頻分量先出現,高頻分量后出現,以增加行程中連續“0”的個數,這63個元素采用了“之”字型(zigzag scan),的排列方法,如下圖所示,
    在這里插入圖片描述

(5) 熵編碼(Huffman編碼)

為了進一步提高壓縮比,需要對RLE編碼結果再進行熵編碼,我們選用Huffman編碼根據使用頻率來最大化節省字符(編碼)的存盤空間,

操作步驟大致如下圖:
將符號按照概率由大到小排隊,編碼時從最小概率的兩個符號開始,可選其中一個支路為0,另一支路為1,然后將已編碼的兩支路的概率合并,并重新按照概率從大到小的順序排隊,多次重復使用上述方法直至合并概率歸一時為止,一般若將新合并后的支路排到等概率的最上支路,將有利于縮短碼長方差,且編出的碼更接近于等長碼
在這里插入圖片描述

3、JPEG解碼原理

JPEG解碼為編碼的逆程序,解碼大致流程如下:

(1)讀入檔案的相關資訊

(2)初步了解影像資料流的結構

(3)顏色分量單元的內部解碼

(4)直流系數的差分編碼

(5)反量化 & 反Zig-zag編碼

(6)反離散余弦變換

二、實驗步驟

1、定義結構體、引數等

(1)struct huffman_table:

存盤Huffman碼表

struct huffman_table
{
  /* Fast look up table, using HUFFMAN_HASH_NBITS bits we can have directly the symbol,
   * if the symbol is <0, then we need to look into the tree table */
  short int lookup[HUFFMAN_HASH_SIZE];
  /* code size: give the number of bits of a symbol is encoded */
  unsigned char code_size[HUFFMAN_HASH_SIZE];
  /* some place to store value that is not encoded in the lookup table 
   * FIXME: Calculate if 256 value is enough to store all values
   */
  uint16_t slowtable[16-HUFFMAN_HASH_NBITS][256];
};

(2)struct component:

儲存當前8×8像塊中有關解碼的資訊

struct component 
{
  unsigned int Hfactor; // 水平采樣因子
  unsigned int Vfactor; // 垂直采樣因子
  float* Q_table;   // 指向該8×8塊使用的量化表
  struct huffman_table *AC_table;   // 指向該塊使用的AC Huffman表
  struct huffman_table *DC_table;   // 指向該塊使用的DC Huffman表
  short int previous_DC;    // 前一個塊的直流DCT系數
  short int DCT[64];    // DCT系數陣列
    
#if SANITY_CHECK
  unsigned int cid;
#endif
};

(3)struct jdec_private:

JPEG資料流的結構體,包含圖片寬高、Huffman碼表等資訊

/* tinyjpeg-internal.h */

struct jdec_private
{
  /* Public variables */
  uint8_t *components[COMPONENTS];  /* 分別指向YUV三個分量的三個指標 */
  unsigned int width, height;	/* 影像寬高 */
  unsigned int flags;

  /* Private variables */
  const unsigned char *stream_begin, *stream_end;
  unsigned int stream_length;

  const unsigned char *stream;	/* 指向當前資料流的指標 */
  unsigned int reservoir, nbits_in_reservoir;

  struct component component_infos[COMPONENTS];
  float Q_tables[COMPONENTS][64];		/* quantization tables */
  struct huffman_table HTDC[HUFFMAN_TABLES];	/* DC huffman tables */
  struct huffman_table HTAC[HUFFMAN_TABLES];	/* AC huffman tables */
  int default_huffman_table_initialized;
  int restart_interval;
  int restarts_to_go;				/* MCUs left in this restart interval */
  int last_rst_marker_seen;			/* Rst marker is incremented each time */

  /* Temp space used after the IDCT to store each components */
  uint8_t Y[64*4], Cr[64], Cb[64];

  jmp_buf jump_state;
  /* Internal Pointer use for colorspace conversion, do not modify it !!! */
  uint8_t *plane[COMPONENTS];
};

2、逐步除錯JPEG解碼器程式,將輸入的JPEG檔案進行解碼

具體程式如下:

 /* 讀取JPEG檔案,進行解碼,并存盤結果 */
int convert_one_image(const char *infilename, const char *outfilename, int output_format)
{
  FILE *fp;
  unsigned int length_of_file;
  unsigned int width, height;
  unsigned char *buf;
  struct jdec_private *jdec;
  unsigned char *components[3];

  /* 把jpeg讀入緩沖區 */
  fp = fopen(infilename, "rb");
  if (fp == NULL)
    exitmessage("Cannot open filename\n");
  length_of_file = filesize(fp);
  buf = (unsigned char *)malloc(length_of_file + 4);
  if (buf == NULL)
    exitmessage("Not enough memory for loading file\n");
  fread(buf, length_of_file, 1, fp);
  fclose(fp);

  /* 解壓縮 */
  jdec = tinyjpeg_init();
  if (jdec == NULL)
    exitmessage("Not enough memory to alloc the structure need for decompressing\n");

  /* 決議檔案頭 */
  if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0)
    exitmessage(tinyjpeg_get_errorstring(jdec));

  /* 計算影像寬高 */
  tinyjpeg_get_size(jdec, &width, &height);

  snprintf(error_string, sizeof(error_string),"Decoding JPEG image...\n");
  if (tinyjpeg_decode(jdec, output_format) < 0)
    exitmessage(tinyjpeg_get_errorstring(jdec));

  /* 
   * Get address for each plane (not only max 3 planes is supported), and
   * depending of the output mode, only some components will be filled 
   * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane
   */
   //提取YUV分量
  tinyjpeg_get_components(jdec, components);

 /* 按照指定的輸出格式保存輸出檔案 */
  switch (output_format)
   {
    case TINYJPEG_FMT_RGB24:
    case TINYJPEG_FMT_BGR24:
      write_tga(outfilename, output_format, width, height, components);
      break;
    case TINYJPEG_FMT_YUV420P:
      write_yuv(outfilename, width, height, components);
      break;
    case TINYJPEG_FMT_GREY:
      write_pgm(outfilename, width, height, components);
      break;
   }

  /* Only called this if the buffers were allocated by tinyjpeg_decode() */
  tinyjpeg_free(jdec);
  /* else called just free(jdec); */

  free(buf);
  return 0;
}

3、將輸出檔案保存為可供YUVViewer觀看的YUV檔案

	//輸出yuv檔案
	snprintf(temp, 1024, "%s.yuv", filename);
	F = fopen(temp, "wb");
	fwrite(components[0], width, height, F);
	fwrite(components[1], width * height / 4, 1, F);
	fwrite(components[2], width * height / 4, 1, F);
	fclose(F);

4、視音頻編解碼除錯中TRACE的目的和含義

頭檔案tinyjpeg.h
TRACE設為1,表示程式正常除錯運行;
TRACE設為0,關閉程式

#define  snprintf _snprintf
#define TRACE 1
#define  TRACEFILE "trace_jpeg.txt"

5、以txt檔案輸出所有的量化矩陣及Huffman碼表

(1)宣告量化矩陣和Huffman碼表的txt檔案

tinyjpeg.h

FILE* quanfile;//宣告量化矩陣txt檔案
FILE* hufffile;//宣告Huffman碼表txt檔案

(2)建立并輸出量化矩陣

tinyjpeg.cbuild_quantization_table()的修改:

static void build_quantization_table(float* qtable, const unsigned char* ref_table)
{
	int i, j;
	static const double aanscalefactor[8] = {
	   1.0, 1.387039845, 1.306562965, 1.175875602,
	   1.0, 0.785694958, 0.541196100, 0.275899379
	};
	const unsigned char* zz = zigzag;

	//輸出所有量化矩陣
	quanfile = fopen("outquan.txt", "a");//打開量化矩陣檔案
	for (i = 0; i < 8; i++) {
		for (j = 0; j < 8; j++) {
			fprintf(quanfile, "%d\t", ref_table[*zz]);//把量化矩陣輸入到txt檔案
			*qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];
		}
		fprintf(quanfile, "\n");
	}

}

(3)量化矩陣檔案的更新寫入

parse_DQT( )

static int parse_DQT(struct jdec_private* priv, const unsigned char* stream)
{
	int qi;//量化表ID
	float* table;// 指向量化表
	const unsigned char* dqt_block_end;// 指向量化表結束位置
#if TRACE
	fprintf(p_trace, "> DQT marker\n");
	fflush(p_trace);
#endif
	dqt_block_end = stream + be16_to_cpu(stream);
	stream += 2;	// 跳過長度欄位

	while (stream < dqt_block_end)// 檢查是否還有量化表
	{
		qi = *stream++; // 將量化表中系數逐個賦給qi
#if SANITY_CHECK
		if (qi >> 4)
			snprintf(error_string, sizeof(error_string), "16 bits quantization table is not supported\n");
		if (qi > 4)
			snprintf(error_string, sizeof(error_string), "No more 4 quantization table is supported (got %d)\n", qi);
#endif
		table = priv->Q_tables[qi];
		build_quantization_table(table, stream);
		stream += 64;
	}
#if TRACE
	fprintf(p_trace, "< DQT marker\n");
	fflush(p_trace);	//更新列印的trace檔案
	fprintf(quanfile, "DQT ID: %d\n", qi);
	fflush(quanfile);	//更新列印量化矩陣
#endif
	return 0;
}

(4)建立并輸出HUFFMAN碼表

static void build_huffman_table(const unsigned char* bits, const unsigned char* vals, struct huffman_table* table)
{
	unsigned int i, j, code, code_size, val, nbits;
	unsigned char huffsize[HUFFMAN_BITS_SIZE + 1], * hz;
	unsigned int huffcode[HUFFMAN_BITS_SIZE + 1], * hc;
	int next_free_entry;

	/*
	 * Build a temp array
	 *   huffsize[X] => numbers of bits to write vals[X]
	 */
	hz = huffsize;
	for (i = 1; i <= 16; i++)
	{
		for (j = 1; j <= bits[i]; j++)
			*hz++ = i;
	}
	*hz = 0;

	memset(table->lookup, 0xff, sizeof(table->lookup));
	for (i = 0; i < (16 - HUFFMAN_HASH_NBITS); i++)
		table->slowtable[i][0] = 0;

	/* Build a temp array
	 *   huffcode[X] => code used to write vals[X]
	 */
	code = 0;
	hc = huffcode;
	hz = huffsize;
	nbits = *hz;
	while (*hz)
	{
		while (*hz == nbits)
		{
			*hc++ = code++;
			hz++;
		}
		code <<= 1;
		nbits++;
	}

	/*
	 * Build the lookup table, and the slowtable if needed.
	 */
	next_free_entry = -1;
	for (i = 0; huffsize[i]; i++)
	{
		val = vals[i];
		code = huffcode[i];
		code_size = huffsize[i];
/*列印輸出Huffman碼表*/
#if TRACE
		fprintf(p_trace, "val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
		fflush(p_trace);
		fprintf(hufffile, "val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
		fflush(hufffile);
#endif
		table->code_size[val] = code_size;
		if (code_size <= HUFFMAN_HASH_NBITS)
		{
			/*
			 * Good: val can be put in the lookup table, so fill all value of this
			 * column with value val
			 */
			int repeat = 1UL << (HUFFMAN_HASH_NBITS - code_size);
			code <<= HUFFMAN_HASH_NBITS - code_size;
			while (repeat--)
				table->lookup[code++] = val;

		}
		else
		{
			/* Perhaps sorting the array will be an optimization */
			uint16_t* slowtable = table->slowtable[code_size - HUFFMAN_HASH_NBITS - 1];
			while (slowtable[0])
				slowtable += 2;
			slowtable[0] = code;
			slowtable[1] = val;
			slowtable[2] = 0;
			/* TODO: NEED TO CHECK FOR AN OVERFLOW OF THE TABLE */
		}

	}
}

(5)Huffman碼表的更新寫入

parse_DHT()

/*列印輸出Huffman碼表*/
static int parse_DHT(struct jdec_private* priv, const unsigned char* stream)
{
	unsigned int count, i;
	unsigned char huff_bits[17];
	int length, index;

	length = be16_to_cpu(stream) - 2;
	stream += 2;	/* Skip length */
#if TRACE
	fprintf(p_trace, "> DHT marker (length=%d)\n", length);
	fflush(p_trace);
#endif
	hufffile = fopen("outhuff.txt", "a");
	while (length > 0) {
		index = *stream++;

		/* We need to calculate the number of bytes 'vals' will takes */
		huff_bits[0] = 0;
		count = 0;
		for (i = 1; i < 17; i++) {
			huff_bits[i] = *stream++;
			count += huff_bits[i];
		}
#if SANITY_CHECK
		if (count >= HUFFMAN_BITS_SIZE)
			snprintf(error_string, sizeof(error_string), "No more than %d bytes is allowed to describe a huffman table", HUFFMAN_BITS_SIZE);
		if ((index & 0xf) >= HUFFMAN_TABLES)
			snprintf(error_string, sizeof(error_string), "No more than %d Huffman tables is supported (got %d)\n", HUFFMAN_TABLES, index & 0xf);
#if TRACE
		fprintf(p_trace, "Huffman table %s[%d] length=%d\n", (index & 0xf0) ? "AC" : "DC", index & 0xf, count);
		fflush(p_trace);
		fprintf(hufffile, "Huffman table %s[%d] length=%d\n", (index & 0xf0) ? "AC" : "DC", index & 0xf, count);
		fflush(hufffile);
#endif
#endif

		if (index & 0xf0)
			build_huffman_table(huff_bits, stream, &priv->HTAC[index & 0xf]);
		else
			build_huffman_table(huff_bits, stream, &priv->HTDC[index & 0xf]);

		length -= 1;
		length -= 16;
		length -= count;
		stream += count;
	}
#if TRACE
	fprintf(p_trace, "< DHT marker\n");
	fflush(p_trace);
#endif
	return 0;
}

四、實驗代碼分析

1、決議JPEG檔案頭函式

JPEG檔案頭函式定位了檔案頭識別符號后的開始位置、長度、以及結束位置:

int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size)
{
  int ret;

  /* Identify the file */
  if ((buf[0] != 0xFF) || (buf[1] != SOI))  // JPEG檔案必須以SOI marker為起始,否則不是合法的JPEG檔案
    snprintf(error_string, sizeof(error_string),"Not a JPG file ?\n");

  priv->stream_begin = buf+2;   // 跳過識別符號
  priv->stream_length = size-2;
  priv->stream_end = priv->stream_begin + priv->stream_length;

  ret = parse_JFIF(priv, priv->stream_begin);   // 開始決議JPEG

  return ret;
}

2、決議SOF

static int parse_SOF(struct jdec_private *priv, const unsigned char *stream)
{
  int i, width, height, nr_components, cid, sampling_factor;
  int Q_table;
  struct component *c;
#if TRACE
  fprintf(p_trace,"> SOF marker\n");
  fflush(p_trace);
#endif
  print_SOF(stream);

  height = be16_to_cpu(stream+3);
  width  = be16_to_cpu(stream+5);
  nr_components = stream[7];
#if SANITY_CHECK
  if (stream[2] != 8)
    snprintf(error_string, sizeof(error_string),"Precision other than 8 is not supported\n");
  if (width>JPEG_MAX_WIDTH || height>JPEG_MAX_HEIGHT)
    snprintf(error_string, sizeof(error_string),"Width and Height (%dx%d) seems suspicious\n", width, height);
  if (nr_components != 3)
    snprintf(error_string, sizeof(error_string),"We only support YUV images\n");
  if (height%16)
    snprintf(error_string, sizeof(error_string),"Height need to be a multiple of 16 (current height is %d)\n", height);
  if (width%16)
    snprintf(error_string, sizeof(error_string),"Width need to be a multiple of 16 (current Width is %d)\n", width);
#endif
  stream += 8;
  for (i=0; i<nr_components; i++) {
     cid = *stream++;
     sampling_factor = *stream++;
     Q_table = *stream++;
     c = &priv->component_infos[i];
#if SANITY_CHECK
     c->cid = cid;
     if (Q_table >= COMPONENTS)
       snprintf(error_string, sizeof(error_string),"Bad Quantization table index (got %d, max allowed %d)\n", Q_table, COMPONENTS-1);
#endif
     c->Vfactor = sampling_factor&0xf;
     c->Hfactor = sampling_factor>>4;
     c->Q_table = priv->Q_tables[Q_table];
#if TRACE
     fprintf(p_trace,"Component:%d  factor:%dx%d  Quantization table:%d\n",
           cid, c->Hfactor, c->Hfactor, Q_table );
	 fflush(p_trace);
#endif

  }
  priv->width = width;
  priv->height = height;
#if TRACE
  fprintf(p_trace,"< SOF marker\n");
  fflush(p_trace);
#endif

  return 0;
}

3、決議SOS

static int parse_SOS(struct jdec_private *priv, const unsigned char *stream)
{
  unsigned int i, cid, table;
  unsigned int nr_components = stream[2];   // 顏色分量數

  stream += 3;
  for (i=0;i<nr_components;i++) {
     /* 得到使用的Huffmann表號 */
     cid = *stream++;
     table = *stream++;
      
     priv->component_infos[i].AC_table = &priv->HTAC[table&0xf];
     priv->component_infos[i].DC_table = &priv->HTDC[table>>4];
  }
  priv->stream = stream+3;
  return 0;
}

4、之字形掃描


static const unsigned char zigzag[64] = 
{
   0,  1,  5,  6, 14, 15, 27, 28,
   2,  4,  7, 13, 16, 26, 29, 42,
   3,  8, 12, 17, 25, 30, 41, 43,
   9, 11, 18, 24, 31, 40, 44, 53,
  10, 19, 23, 32, 39, 45, 52, 54,
  20, 22, 33, 38, 46, 51, 55, 60,
  21, 34, 37, 47, 50, 56, 59, 61,
  35, 36, 48, 49, 57, 58, 62, 63
};

五、除錯與結果分析

0、設定命令引數

解碼的jpg檔案 /yuv420p / 輸出檔案前綴(中間空格隔開)

這一行命令引數表示將test.jpg檔案轉換為yuv420格式的前綴為output檔案

在這里插入圖片描述

1、解碼JPEG生成的YUV檔案

在這里插入圖片描述

在這里插入圖片描述

2、生成量化矩陣檔案outquan.txt

在這里插入圖片描述
在這里插入圖片描述

3、生成Huffman碼表

在這里插入圖片描述

六、實驗總結

1、本實驗通過Visual Studio實作,
2、通過本實驗掌握了JPEG編解碼系統的基本原理以及JPEG的格式分析,
3、在程式除錯中理解程式設計的整體框架以及三個結構體的設計目的,同時理解了TRACE在視音頻編解碼除錯中的目的和含義,
4、初步掌握了復雜的資料壓縮演算法實作,并能根據理論分析需要實作所對應資料的輸出,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/286501.html

標籤:其他

上一篇:機器學習之單變數線性回歸(吳恩達機器學習筆記)

下一篇:JPEG原理分析及JPEG解碼器的除錯

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more