2019-03-12 20:10:32 qq_42655135 阅读数 317

图像处理RGB通道与灰度化

提取RGB三个通道并显示,其中P为原始图像

  P=imread('picture1.png');
 subplot(1,4,1),imshow(P),title('原图像');
 subplot(1,4,2),imshow(P(:,:,1)),title('r');
 subplot(1,4,3),imshow(P(:,:,2)),title('g');
 subplot(1,4,4),imshow(P(:,:,3)),title('b');

matlab运行结果
matlab结果
绿色和蓝色通道互换

P=imread('picture1.png');
Q=P;
Q(:,:,2)=P(:,:,3);
Q(:,:,3)=P(:,:,2);
subplot(1,2,1),imshow(P),title('原图像');
subplot(1,2,2),imshow(Q),title('互换g,b通道后图像');

利用公式来将彩色图像转化为灰度图像

Y=0.299R+0.587G+0.114B
I=(R+G+B)/3;*

R=P(:,:,1);
G=P(:,:,2);
B=P(:,:,3);
Y=0.299*R+0.587*G+0.114*B;
I=(R+G+B)/3;
subplot(1,3,1),imshow(P),title('原始图像');
subplot(1,3,2),imshow(I),title('I分量');
subplot(1,3,3),imshow(Y),title('Y分量,灰度图像');

在这里插入图片描述

利用MATLAB自带函数来转化灰度图像

gray=rgb2gray(P);
figure;
imshow(gray),titile('函数灰度图像');

在这里插入图片描述

2016-01-28 10:48:57 u011896903 阅读数 1713
/**
 * 图像处理线程
 * 获取图像的rgb平均值
 */
class myThread implements Runnable {
  public void run() {
      BitmapDrawable db = (BitmapDrawable) getResources().getDrawable(R.mipmap.mirror);
      Bitmap bitmap = db.getBitmap();
      int width = bitmap.getWidth();
      int hight = bitmap.getHeight();
      int[] pixs = new int[width*hight];
        int sum_r = 0;
        int sum_g = 0;
        int sum_b = 0;
        int sum_a = 0;
        int cunt = 0;
      bitmap.getPixels(pixs, 0, width, 0, 0, width, hight);
      for (int i =0;i<width*hight;i++){
        int r = Color.red(pixs[i]);
        int g = Color.green(pixs[i]);
        int b = Color.blue(pixs[i]);
        int a = Color.alpha(pixs[i]);

        //去除黑色点
        if (r!=0 && g!=0 && b!=0){
          sum_r+=r;
          sum_g+=g;
          sum_b+=b;
          sum_a+=a;
          cunt++;
        }
      }
      //color数组中存放平均之后的rgb值
      int[] color = new int[4];
      color[0] = sum_r/cunt;
      color[1] = sum_g/cunt;
      color[2] = sum_b/cunt;
      color[3] = sum_a/cunt;


  }
}
2016-02-03 21:47:37 jaych 阅读数 2195

最近在项目的过程中需要用到 YUV 的 Y通道数据,但是原始数据图像为RGB格式,所以自己写了一个RGB2YUV的程序,并且进行优化,对此总结如下。

RGB2YUV 原理

RGB及YUV是两种不同的颜色空间,具体可以换算关系如下:

这里写图片描述

根据该换算关系,我们直接可以得到Y通道数据。

程序1

void rgb2yuv2(unsigned char *R,unsigned char *G,unsigned char *B,unsigned char *Y,int len)
{
//这里应有对指针的有效性判断,此处略
    for(int i=len;i!=0;i--){
        *Y++ = *R*0.299 + *G*0.587 + *B*0.114;
        R++;B++;G++;
    }

}

优化思路

不过这里涉及大量的浮点数运算,使得程序运行十分缓慢,为了加速,我们可以采用查表法及定点运算进行优化。

1、查表法

因为R/G/B通道的系数都已经固定了,只要预先求出[0..255]这些数值乘以系数对应的数值,在读取到对应R通道数据时,可以通过查表形式获取。

2、定点运算

由于系数均为小数点3位数,我们可以 先乘以299再除以1000 达到 乘以0.299 的目的。
同时,为了简化乘法,采用移位操作,向右移位10bit,则表示除以1024,对应的,我们只要在生成 查表数值 的时候,乘以1024即可。

综合1、2,我们可以先将:

对于R通道,[0..255] 乘以 0.299,再乘以1024,得到 256个对应的数值。G/B通道也采取类似操作。
在计算Y通道时,取出R/G/B通道对应的数值,求和并右移10位,得到最终数据。

程序2

int array[256];
// 生成各个通道对应的数值,并保存至表格
void genArray(float factor){ // factor是对应通道的系数。
    int i=0;
    for(i=0;i<256;i++){
        array[i]=(int)(factor*i*1024+0.5); 
    }
}

// RGB转YUV
void rgb2yuv(unsigned char *R,unsigned char *G,unsigned char *B,unsigned char *Y,int len)
{
//这里应有对指针的有效性判断,此处略
         for(int i=len;i!=0;i--){
               *Y++ = (RT[*R++]+GT[*G++]+BT[*B++])>>10;
        }

}

经验证,实际得到的图像与程序1得到的图像类似,误差为±1

2017-05-09 00:31:05 weierqiuba 阅读数 713

YUV格式具有亮度信息和色彩信息分离的特点,但大多数图像处理操作都是基于RGB格式。
因此当要对图像进行后期处理显示时,需要把YUV格式转换成RGB格式。
RGB与YUV的变换公式如下:
这里写图片描述

YUV(256 级别) 可以从8位 RGB 直接计算:

Y = 0.299 R + 0.587 G + 0.114 B
U = - 0.1687 R - 0.3313 G + 0.5 B + 128
V = 0.5 R - 0.4187 G - 0.0813 B + 128

反过来,RGB 也可以直接从YUV (256级别) 计算:

R = Y + 1.402 (V-128)
G = Y - 0.34414 (U-128) - 0.71414 (V-128)
B = Y + 1.772 (U-128)

例程:
按照YUV与RGB的变换公式,逐像素访问Y、U、V分量的值,并转换成RGB:

bool YV12ToBGR24_Native(unsigned char* pYUV,unsigned char* pBGR24,int width,int height)
{
    if (width < 1 || height < 1 || pYUV == NULL || pBGR24 == NULL)
        return false;
    const long len = width * height;
    unsigned char* yData = pYUV;
    unsigned char* vData = &yData[len];
    unsigned char* uData = &vData[len >> 2];

    int bgr[3];
    int yIdx,uIdx,vIdx,idx;
    for (int i = 0;i < height;i++){
        for (int j = 0;j < width;j++){
            yIdx = i * width + j;
            vIdx = (i/2) * (width/2) + (j/2);
            uIdx = vIdx;

            bgr[0] = (int)(yData[yIdx] + 1.732446 * (uData[vIdx] - 128));                                    // b分量
            bgr[1] = (int)(yData[yIdx] - 0.698001 * (uData[uIdx] - 128) - 0.703125 * (vData[vIdx] - 128));    // g分量
            bgr[2] = (int)(yData[yIdx] + 1.370705 * (vData[uIdx] - 128));                                    // r分量

            for (int k = 0;k < 3;k++){
                idx = (i * width + j) * 3 + k;
                if(bgr[k] >= 0 && bgr[k] <= 255)
                    pBGR24[idx] = bgr[k];
                else
                    pBGR24[idx] = (bgr[k] < 0)?0:255;
            }
        }
    }
    return true;
}
2019-03-08 09:10:27 weixin_42927264 阅读数 1131

图像处理技术(RGB分离)

在这里插入图片描述
最近学习了图像处理技术,第一个小工程做的事将一张图片的rgb分离,存为三张图片,就像PS中的RGB通道的三张图片一样。

我们先准备两张24位真彩色图片,一张宽度像素为4的倍数,一张则不是。

我们来看下它的文件头和信息头都储存了什么信息:

位图文件头BITMAPFILEHEADER
这是一个结构,其定义如下:

typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;

这个结构的长度是固定的,为14个字节(WORD为无符号16位整数,DWORD为无符号32位整数),各个域的说明如下:
bfType
指定文件类型,必须是0x424D,即字符串“BM”,也就是说所有.bmp文件的头两个字节都是“BM”。
bfSize
指定文件大小,包括这14个字节。
bfReserved1,bfReserved2
为保留字,不用考虑
bfOffBits
为从文件头到实际的位图数据的偏移字节数

位图信息头BITMAPINFOHEADER
这也是一个结构,其定义如下:

typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;

这个结构的长度是固定的,为40个字节(LONG为32位整数),各个域的说明如下:
biSize
指定这个结构的长度,为40。
biWidth
指定图象的宽度,单位是像素。
biHeight
指定图象的高度,单位是像素。
biPlanes
必须是1,不用考虑。
biBitCount
指定表示颜色时要用到的位数,常用的值为1(黑白二色图), 4(16色图), 8(256色), 24(真彩色图)(新的.bmp格式支持32位色,这里就不做讨论了)。
biCompression
指定位图是否压缩,有效的值为BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS(都是一些Windows定义好的常量)。要说明的是,Windows位图可以采用RLE4,和RLE8的压缩格式,但用的不多。我们今后所讨论的只有第一种不压缩的情况,即biCompression为BI_RGB的情况。
biSizeImage
指定实际的位图数据占用的字节数,其实也可以从以下的公式中计算出来:
biSizeImage=biWidth’ × biHeight
要注意的是:上述公式中的biWidth’必须是4的整倍数(所以不是biWidth,而是biWidth’,表示大于或等于biWidth的,最接近4的整倍数。举个例子,如果biWidth=240,则biWidth’=240;如果biWidth=241,biWidth’=244)。
如果biCompression为BI_RGB,则该项可能为零
biXPelsPerMeter
指定目标设备的水平分辨率,单位是每米的象素个数,关于分辨率的概念。
biYPelsPerMeter
指定目标设备的垂直分辨率,单位同上。
biClrUsed
指定本图象实际用到的颜色数,如果该值为零,则用到的颜色数为2biBitCount。
biClrImportant
指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。

一开始我想将原图的每个像素点取出来,然后将RGB分量取出来分别赋值,这样处理对于宽度为4的倍数的图片是没有问题的。但是到了不是4倍数的图片就出问题了。

后来了解到图片的读取和储存都是按字节来进行,而且是必须要是4 的倍数,那我们的解决方案就明确了,把所有字节读出来后再赋值。

那么我们怎么样读出所有的字节来呢?

if (bmpWidth % 4 != 0) {
		bmpWidth = (bmpWidth * infoHeader.biBitCount / 8 + 3) / 4 * 4;
	}
	else {
		bmpWidth = bmpWidth * infoHeader.biBitCount / 8;
	}

利用这个公式转换宽度,再乘以高度就是所有字节的数量了。

下面附上代码:

#pragma once
#include<iostream>
#include<fstream>
#include<Windows.h>

using namespace std;



bool readBmp(char *bmpName) {
	FILE *fb = fopen(bmpName, "rb");
	FILE* pfoutr = fopen("r.bmp", "wb");
	FILE* pfoutg = fopen("g.bmp", "wb");
	FILE* pfoutb = fopen("b.bmp", "wb");
	if (fb == 0) {
		return 0;
	}
	BITMAPFILEHEADER fileHeader;
	BITMAPINFOHEADER infoHeader;
	int bmpWidth =0;//图像的宽
	int bmpHeight=0;//图像的高
	int bmpOffset = 0;

	fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, fb);
	fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, fb);

	bmpHeight = infoHeader.biHeight;
	bmpWidth = infoHeader.biWidth;
	bmpOffset = fileHeader.bfOffBits;
	
	if (bmpWidth % 4 != 0) {
		bmpWidth = (bmpWidth * infoHeader.biBitCount / 8 + 3) / 4 * 4;
	}
	else {
		bmpWidth = bmpWidth * infoHeader.biBitCount / 8;
	}
	
	if (infoHeader.biBitCount >= 1) {
		
		int size1 = bmpHeight * bmpWidth;
		BYTE *img = new BYTE[size1];
		BYTE *img1 = new BYTE[size1];
		BYTE *img2 = new BYTE[size1];
		BYTE *img3 = new BYTE[size1];
		
		fseek(fb, bmpOffset, 0);
		fread(img, sizeof(BYTE), size1, fb);

		for (int i = 0;i < bmpHeight ;i++) {
			for (int j = 0;j < bmpWidth;j++) {
					switch (j % 3) {
					case 0:
						img1[i*bmpWidth + j] = 0;
						img2[i*bmpWidth + j] = 0;
						img3[i*bmpWidth + j] = img[i*bmpWidth + j];
						break;
					case 1:
						img1[i*bmpWidth + j] = 0;
						img2[i*bmpWidth + j] = img[i*bmpWidth + j];
						img3[i*bmpWidth + j] = 0;
						break;
					case 2:
						img1[i*bmpWidth + j] = img[i*bmpWidth + j];
						img2[i*bmpWidth + j] = 0;
						img3[i*bmpWidth + j] = 0;
						break;
					}
				
				
			}
		}
		fwrite(&fileHeader, sizeof(fileHeader), 1, pfoutr);
		fwrite(&infoHeader, sizeof(infoHeader), 1, pfoutr);
		fwrite(img1, sizeof(BYTE), size1, pfoutr);
		fwrite(&fileHeader, sizeof(fileHeader), 1, pfoutg);
		fwrite(&infoHeader, sizeof(infoHeader), 1, pfoutg);
		fwrite(img2, sizeof(BYTE), size1, pfoutg);
		fwrite(&fileHeader, sizeof(fileHeader), 1, pfoutb);
		fwrite(&infoHeader, sizeof(infoHeader), 1, pfoutb);
		fwrite(img3, sizeof(BYTE), size1, pfoutb);
	}


	
	fclose(fb);
	fclose(pfoutr);
	fclose(pfoutg);
	fclose(pfoutb);
	return 1;
}

int main() {
	char bmpName[] = "sea.bmp";
	readBmp(bmpName);
	
}


这代码我就是测试用,写代码时要注意规范,提取函数哈!

原图:
在这里插入图片描述

R通道:在这里插入图片描述

G通道:
在这里插入图片描述

没有更多推荐了,返回首页