2017-02-25 15:54:00 attilax 阅读数 427

atitit.颜色查找 根据范围  图像处理 inRange 

 

使用opencvinRange 结果又问题,不能找到。调整多次,麻烦,只好使用java实现。

 

原理就是判断范围,如果是的设置为白色,否则黑色。

 

/atiplat_img/src/com/attilax/img/CoreImg.java

 

public static BufferedImage inRange(BufferedImage src, HSV low, HSV hi) {

BufferedImage dst=imgx.new_BackgroudColor_black(src.getWidth(), src.getHeight());

HsvRangeV2 hr=new HsvRangeV2(low, hi);

 ImgTraver_lineScaner itl=new ImgTraver_lineScaner(src);

 itl.cur_Pix_Point_process_Fun_Handler=p->{

  int clr_int=src.getRGB(p.x,p. y);

 Color clr=new Color(clr_int);

 HSV hsv=ColorUtil.rgb2hsv(clr_int);

 if(p.x==409 && p.y==257)

 {

 System.out.println("dbg");

 }

 if(hr.contain(hsv))

 {

 dst.setRGB(p.x,p. y, Color.white.getRGB());

 }

 

 };

 itl.trav();

return dst;

}

:: 绰号:老哇的爪子claw of Eagle 偶像破坏者Iconoclast image-smasher

捕鸟王"Bird Catcher  kok  虔诚者Pious 宗教信仰捍卫者 Defender Of the Faith. 卡拉卡拉红斗篷 Caracalla red cloak 万兽之王

简称:: Emir Attilax Akbar 埃米尔 阿提拉克斯 阿克巴

全名::Emir Attilax Akbar bin Mahmud bin  attila bin Solomon bin adam Al Rapanui 埃米尔 阿提拉克斯 阿克巴 马哈茂德 阿提拉 所罗门 本亚当  阿尔 拉帕努伊

常用名:艾提拉(艾龙),  EMAIL:1466519819@qq.com

 

 

头衔:uke总部o2o负责人,全球网格化项目创始人,

uke交友协会会长  uke捕猎协会会长 Emir Uke部落首席大酋长,

 

uke宗教与文化融合事务部部长, uke宗教改革委员会副主席

uke制度与重大会议委员会委员长,uke保安部首席大队长,uke制度检查委员会副会长,

 

uke 首席cto   软件部门总监 技术部副总监  研发部门总监主管  产品部副经理 项目部副经理   uke科技研究院院长uke软件培训大师

 

uke波利尼西亚区大区连锁负责人 汤加王国区域负责人 uke克尔格伦群岛区连锁负责人,莱恩群岛区连锁负责人,uke布维岛和南乔治亚和南桑威奇群岛大区连锁负责人

 Uke软件标准化协会理事长理事长 Uke 数据库与存储标准化协会副会长

 

uke终身教育学校副校长   Uke医院 与医学院方面的创始人

 uec学院校长, uecip图像处理机器视觉专业系主任   uke文档检索专业系主任

Uke图像处理与机器视觉学院首席院长

Uke 户外运动协会理事长  度假村首席大村长   uke出版社编辑总编

 

转载请注明来源:attilax的专栏  ?http://blog.csdn.net/attilax

--Atiend  v8

 

2012-03-04 18:47:36 giantchen547792075 阅读数 4480
 

目标

我们会寻求下列问题的答案:

l   如何单独扫过图像的每个像素?

l   如何存储 OpenCV 矩阵值?

l   如何衡量我们的算法的性能?

l   什么是查找表和为什么使用查找表?

我们测试用例

让我们先从一种简单的色彩减弱方法开始考虑。使用C 和 C++的无符号的字符类型矩阵项存储像素的通道最多可能有256个不同值。对于三个通道的图像,这可以在允许的方式下形成非常多颜色(确切地说有1600万)。处理使用那么多不同色调的颜色可能会严重影响我们的算法性能。但是,有时处理与他们相较少了很多的图象就足以获得相同的最终结果。

在此情况下,我们使颜色空间减少是常见的。这意味着我们以一个新的输入值划分当前的颜色空间,最终得到较少的颜色。例如每个值介于零和九之间设为0,在10到19之间就设置为10,以此类推。

当您在使用int值划分 uchar 时(无符号的字符-也可以视为介于 0 和 255 之间的值)结果的值也将 char。这些值可能只是 char 值。因此,任何分数将向下舍入。利用这一事实向上运算中的 uchar 域可表示为:

                           

一种简单的颜色空间减少算法将由只是遍历图像矩阵的每个像素和在每个像素上应用此公式组成。我们做的除法和乘法运算毫无价值,而且这些操作是代价极其高的操作。如果可能的话,通过使用代价更低的操作,如几个减法和加法来避免他们是值得的,或在最好的情况下通过简单的赋值。此外,请注意我们只有有限的上操作的输入值。Uchar 体系的情况下,这值的确切值是256。

因此,对于较大的图像明智之举是在计算之前和期间分配的所有可能值只是通过使用查找表进行分配。 查找表是一个简单的数组(有一个或多个维度)为给定的输入的值保存最终输出值。其优点在于我们不需要计算,我们只需要读取结果。

我们的测试用例程序 (和这里介绍的示例) 将执行以下操作: 控制台命令行参数图像 (即也可以任意一种彩色或灰度-控制台行参数) 中的读取并应用给定的控制台命令行参数整数值来减少。在OpenCV中,现在逐像素遍历图像的像素的他们是三种主要方法。若要使事情更有趣,使每个图像扫描使用所有这些方法,和打印出花了多长时间。

您可以在这里下载完整的源代码或在OpenCV 的cpp 教程代码核心的部分的示例目录中查到。其基本的用法是:

how_to_scan_images  imageName.jpg  intValueToReduce  [G]

最后一个参数是可选的。 如果加载给定图像中的灰度格式,否则使用RGB颜色的方式。 首要的事是计算查找表。

int divideWith; // 将输入的字符串转换成数字 - C++ style

stringstream s;

s << argv[2];

s >> divideWith;

if (!s)

{

cout << "Invalid number entered for dividing. " << endl;

return -1;

}

uchar table[256];

for (int i = 0; i < 256; ++i)

table[i] = divideWith*(i/divideWith);


 

这里,我们首先使用c++的stringstream类将第三个命令行参数从文本转换为一个整数格式。然后然后我们用一个简单的查找(look)和上面的公式计算查找表。 这里没有OpenCV具体的东西。

另一个问题是我们如何衡量时间?那么OpenCV提供两个简单的函数来实现它:

getTickCount() 和 getTickFrequency()。前者返回系统CPU完成某些事件发出信号的次数(比如来自你启动你的系统这个事件)。后者返回每一秒你的系统CPU发出多少次信号。以此来计算两个操作之间使用的秒数就简单了,如:

double t = (double)getTickCount();

// 发生的事件 ...

t = ((double)getTickCount() - t)/getTickFrequency();

cout << "Times passed in seconds: " << t << endl;


 

如何在内存中存储图像矩阵?

正如你可能已经在我的Mat-基本图像容器教程中读到的那样,矩阵的大小取决于所使用的颜色系统。更准确的说,这取决于使用的通道数。灰度图像的情况下,我们有类似:

多通道图像的列包含通道的数量一样多的子列,例如在RGB色彩系统下:

请注意,通道的顺序是反的:是BGR而不是RGB。由于在许多情况下,内存很大可能足以以连续的方式在另一个后一行跟着一行存储数据行,创建一个长行。因为所有的东西都是一个空间接着下一个空间,这将有助于加快扫描过程。如果是这种情况,我们可以使用isContinuous() 函数来查看矩阵。请继续阅读下一部分的例子。

有效的方式

在性能方面,你敌不过经典C风格运算符[](指针)访问。 因此,我们推荐的最有效的完成任务的方法是:

Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)

{

// 只接受char类型矩阵

CV_Assert(I.depth() != sizeof(uchar));

int channels = I.channels();

int nRows = I.rows*channels;

int nCols = I.cols;

if (I.isContinuous())

{

nCols*= nRows;

nRows = 1;

}

int i,j;

uchar* p;

for( i = 0; i < nRows; ++i)

{

p = I.ptr<uchar>(i);

for ( j = 0; j < nCols; ++j)

{

p[j] = table[p[j]];

}

}

return I;

}


这里,我们基本上只是获取一个指针,指向每一行的开始,然后遍历它直到它结束。 在特殊情况下, 矩阵是以一种持续的方式存储的我们只需要请求一次指针单和一路下来直到结束。 我们需要查看彩色图像:我们有三个通道,所以在每行中我们要遍历3倍多的项。

迭代(安全)方法

有效的方式,确保您遍历适量的 uchar 字段和跳过行之间可能产生的空白是你的责任。迭代器方法被认为是更安全的方式,因为它从用户接管这些任务。您需要做的就是访问图像矩阵的开头和结尾,然后只是增加迭代器的begin,直到到达end。若要获取指出通过迭代器使用的值 * 运算符 (添加在它之前)。

Mat&  ScanImageAndReduceIterator(Mat& I, const uchar* const table)

{

// 只接受char类型矩阵

CV_Assert(I.depth() != sizeof(uchar));

const int channels = I.channels();

switch(channels)

{

case 1:

{

Mat Iterator_<uchar> it, end;

for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)

*it = table[*it];

break;

}

case 3:

{

Mat Iterator_<Vec3b> it, end;

for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)

{

(*it)[0] = table[(*it)[0]];

(*it)[1] = table[(*it)[1]];

(*it)[2] = table[(*it)[2]];

}

}

}

return I;

}


彩色图像的情况下,我们有三个的 uchar 项目,每个列。这可以被视为一个短的 uchar 项目向量,在OpenCV已被以 Vec3b 名称命名了。若要访问 第n个 子列,我们使用简单的运算符 [] 访问。请务必记住 OpenCV 迭代器遍历各列并自动跳转到下一行。因此彩色图像的情况下如果您使用 uchar 简单迭代器您将只能够访问蓝色通道的值。

用返回的引用进行快速地址计算

最后这种方法并不被建议进行扫描。它已获得或以某种方式修改图像中的随机元素。其基本的用法是项目的指定您要访问的行和列数。你可能已经注意到我们之前的描方法中我们正在看图像是通过何种类型的是非常重要的。这里不同它没有作为在自动查找使用何种类型,您需要手动指定。您可以在下面的源代码 (+at() 函数的使用) 的灰度图像的情况下观察到这一点:

Mat&  ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table)

{

// 只接受char类型矩阵

CV_Assert(I.depth() != sizeof(uchar));

const int channels = I.channels();

switch(channels)

{

case 1:

{

for( int i = 0; i < I.rows; ++i)

for( int j = 0; j < I.cols; ++j )

I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];

break;

}

case 3:

{

Mat_<Vec3b>_I = I;

for( int i = 0; i < I.rows; ++i)

for( int j = 0; j < I.cols; ++j )

{

_I(i,j)[0] = table[_I(i,j)[0]];

_I(i,j)[1] = table[_I(i,j)[1]];

_I(i,j)[2] = table[_I(i,j)[2]];

}

I =_I;

break;

}

}

return I;

}


函数需要你的输入类型和坐标,并计算查询的项目的动态地址,然后返回的引用。当你设定一个值时止可能是一个不确定的值,当你获取一个值时这可能是一个恒定的值。作为一个只在debug模式下的安全步骤 * 执行您输入坐标的有效性检查并确定其存在。如果这并不是这样的,你将在标准错误输出流里获得这个漂亮的输出消息。与有效的方式相比,在release模式中使用该方法唯一不同的是,你将为每个图像元素所使用的 C 运算符 []获取新行的指针,然后通过该指针获取获取列的元素。

如果您需要使用这种方法查找多个图像将可能是麻烦的,耗时输入的类型和在访问的每个关键字;OpenCV 的 Mat_数据类型可以解决这个问题。与Mat相同,它需要额外地在定义是您需要根据你在数据矩阵查看什么来指定的数据类型,但是相应地,您可以使用operator()对项进行快速访问。若要使事情更好,很容易就可通过和常用的Mat数据类型相互转换。此示例使用,您可以看到的彩色图像上述函数的运行情况如下。不过,必须注意的是相同的操作 (具有相同的运行时速度) at() 函数也可以做到。这样写只是一种那些懒程序员为了少写几行代码的戏法。

Core模块中的函数

这是实现查找表修改图像中的额外的方法。因为图像处理时您想要替换所有给定的图像中值为其他值是很常见的, OpenCV 有一个函数,不需要修改你写的扫描图像过程。我们使用Core模块的LUT () 函数。首先我们生成查Mat的类型的找表:

Mat lookUpTable(1, 256, CV_8U);

uchar* p = lookUpTable.data;

for( int i = 0; i < 256; ++i)

p[i] = table[i];


最后调用这个函数(I是我们的输入图象而J是输出图像):

LUT(I, lookUpTable, J);


 

性能差异

为达到最佳效果编译该程序并运行依据您自己的CPU速度。为了更好地展示的时间上的差别使用了一个相当大的 (2560 X 1600) 图像。此处提供的演示图像是彩色的图像。更准确的值我已经平均了数百该函数的调用次接到的值。

Efficient  Way

Iterator

On-The-Fly  RA

LUT  function

79.4717milliseconds

83.7201  milliseconds

93.7878  milliseconds

32.5759  milliseconds

 

 

 

 

 

我们可以得出以下几个结论。可能的话,使用已的 OpenCV (而重新构建这些) 的功能,最快的方法是LUT()函数。这是因为 OpenCV 库是启用通过英特尔线程构建块的多线程。但是,如果您需要编写扫描简单的图像推荐使用指针的方法。迭代器肯定是一个更安全的方法,但是很慢。完整图像扫描使用快速引用的访问方法是在debug模式中代价最高的。在release模式下它有可能胜过迭代器方法,但是它一定会此为牺牲迭代器所具有的安全特质。

最后,你可能在YouTube频道的video posted上看到一个示例程序运行。

2018-07-06 17:18:12 attitude_yu 阅读数 1493

列出数据增强的API,方便使用时可快速查找!!!

1. 仿射变换

       在图像处理过程中,当遇到小样本问题时,就需要去做数据增强。数据增强的方式有:随机裁剪、旋转图像、剪切图像、局部弯曲图像、色彩转换(改变RGB通道的颜色)

       数据增强的操作又是基于仿射变换矩阵的,获得新图像的标注坐标也可基于此矩阵来计算,而不需要去重新标注,所以有必要去深究一下其内容。

2. Python API

#! -*coding = UTF-8-*
import cv2
import numpy as np

#读取图片
img = cv2.imread("lena.jpg")
print(type(img))#数组类型
cv2.namedWindow("Lena")
#显示图片
cv2.imshow("Lena", img)
#等待
# cv2.waitKey(0)

#获得图片维度
h,w = img.shape[:2]
print("三维维度: ",img.shape)
print("高和宽: ",h,w)

#保存图片为png格式
cv2.imwrite("lena_png.png", img)

#颜色空间转换  转化为灰度图
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imshow("RGB_lena", RGB_img)
# cv2.waitKey(0)
print("三维维度: ",RGB_img.shape)

#将图片转化为矩阵
array_img = np.array(img)
print(np.asarray(img)[0][0])
print(array_img[0][0])

#图片数据的归一化
norm_img = (array_img/255.0) * 2.0 -1.0
print(norm_img[0][0])

#创建一张图片
create_img = np.zeros((400,400,3), dtype="uint8")

#绘制直线 (图片,起始点,终点,颜色)
color = (255, 0, 0)
cv2.line(create_img, (0,0), (400,400), color)

#绘制矩形 (图片, 左上角, 右下角, 颜色)
cv2.rectangle(create_img, (100,100), (200,200), color)

#绘制圆 (图片, 圆心, 半径, 颜色)
cv2.circle(create_img, (100,100), 100, color)
# cv2.namedWindow("create_img")
# cv2.imshow("create_img", create_img)
# cv2.waitKey(0)

# 调整图片为指定大小
resize_img = cv2.resize(img, (50,50))
# 调整图片为指定比例  插值方法:最近邻插值、双线性插值、基于局部像素重采样
resize_img = cv2.resize(img, (0,0), fx=0.5, fy=0.5,
                        interpolation=cv2.INTER_NEAREST)
print("resize 图像维度:", resize_img.shape)

# 旋转图像 首先根据指定角度获得旋转矩阵,然后仿射图像
center = (img.shape[1]//2, img.shape[0]//2)
# 旋转的中心坐标,旋转角度,输出图像大小
rotate_matrix = cv2.getRotationMatrix2D(center, 90, 1)
rotate_img = cv2.warpAffine(img, rotate_matrix, center)


# 裁剪图像  需指定裁剪范围
crop_img = img[100:200, 100:200]

# 填充图像pad区域 上下左右填充像素数量,边界的处理方法:复制最边缘像素、以常量扩充边界
pad_img = cv2.copyMakeBorder(img, 10,10,10,10,cv2.BORDER_CONSTANT, value=(0,0,255))
print("填充图像维度:", pad_img.shape )

# 平移图像 首先指定平移矩阵,然后仿射变换图像
x_shift=50
y_shift=50
trans_size = (img.shape[1]-100, img.shape[0]-100)
trans_matrix = np.float32([[1,0,x_shift],[0,1,y_shift]])
trans_img = cv2.warpAffine(img, trans_matrix, trans_size)
print("平移图像维度:",trans_img.shape)

# 翻转图像 指定图像翻转模式:1 水平翻转 0 垂直翻转 -1 水平垂直翻转
flip_up_down_img = cv2.flip(img, 1)
flip_left_right_img = cv2.flip(img, 0)
flip_hori_vert_img = cv2.flip(img, -1)

3. TensorFlow API

#! -*- coding=UTF-8 -*-
import tensorflow as tf
import matplotlib.pyplot as plt

# 读取图片
img = tf.gfile.FastGFile("plate.jpg",'rb').read()
# print(img)

# 建立会话
with tf.Session() as sess:
    # 解码图像
    img_decode = tf.image.decode_jpeg(img)
    # print(img_decode.eval())

    # # 保存图像,首先编码图像
    # img_encode = tf.image.encode_jpeg(img_decode)
    # # print(img_encode)
    # with tf.gfile.GFile("new_plate.jpg",'wb') as file:
    #     file.write(img_encode.eval())

    # 调整图片大小,首先将图像数据转化为实数类型,即归一化
    img_decode_norm = tf.image.convert_image_dtype(img_decode, dtype=tf.float32)
    img_resize = tf.image.resize_images(img_decode_norm, [100,200], method=0)
    # print("调整后图像的维度:",img_resize.shape)

    # 自动裁剪、自动填充图像大小
    img_crop = tf.image.resize_image_with_crop_or_pad(img_decode, 100,100)
    img_pad = tf.image.resize_image_with_crop_or_pad(img_decode,1000,1000)

    # 比例调整图像大小
    img_ratio = tf.image.central_crop(img_decode, 0.4)

    # 图像翻转 上下、左右、对角线
    img_up_down = tf.image.flip_up_down(img_decode)
    img_left_right = tf.image.flip_left_right(img_decode)
    img_transpose = tf.image.transpose_image(img_decode)

    # 随机翻转图像 50概率
    img_random_up_down = tf.image.random_flip_up_down(img_decode)
    img_random_left_right = tf.image.random_flip_left_right(img_decode)

    # 图像亮度调整,调整后为保证像素值在0-1或者0-255的范围内,需要截断操作
    img_reduce_brightness = tf.image.adjust_brightness(img_decode_norm, -0.5)
    img_add_brightness = tf.image.adjust_brightness(img_decode_norm, 0.5)
    img_reduce_brightness = tf.clip_by_value(img_reduce_brightness, 0.0, 1.0)


    # 图像对比度调整 按倍数增加或减少
    img_reduce_contrast = tf.image.adjust_contrast(img_decode_norm, 0.5)
    img_add_contrast = tf.image.adjust_contrast(img_decode_norm, 5)

    # 图像色相调整
    img_reduce_hue = tf.image.adjust_hue(img_decode_norm, 0.1)
    img_add_hue = tf.image.adjust_hue(img_decode_norm, -0.1)
    img_reduce_hue = tf.clip_by_value(img_reduce_hue, 0.0, 1.0)

    # 图像饱和度调整
    img_reduce_saturation = tf.image.adjust_saturation(img_decode_norm, -0.5)
    img_add_saturation = tf.image.adjust_saturation(img_decode_norm, 0.5)
    img_reduce_saturation = tf.clip_by_value(img_reduce_saturation, 0.0, 1.0)

    # 图像标准化 将像素调整为均值为0,方差为1
    img_norm = tf.image.per_image_standardization(img_decode_norm)

    #可视化图像
    plt.imshow(img_reduce_saturation.eval())
    plt.show()
2019-09-08 21:07:50 qq_41498261 阅读数 69

LUT

LUT是:Look Up Table(颜色查找表)。
通过LUT,可以将一组RGB值输出为另一组RGB值,从而改变画面的曝光与色彩。

  • 作用
    避免对每一个像素都进行一次计算。预先计算每个像素值的对应的匹配值,然后直接对原图中的像素值在LUT中进行查找,即可快速得到匹配值,减少大量不必要的计算。

  • LUT 不单单用于图像中。在数据处理中,只要知道原始数据范围、变换公式、变换后得到的数据,也可以使用LUT加快速度。

  • LUT实际用途:将一个颜色空间的图匹配到另一个颜色空间;将某个对比度的图匹配到另一对比度;图像增强、产生伪彩色等;


在这里插入图片描述
上图中每个格子代表一个像素,左图有30和40两种像素值,经过LUT之后,40匹配到90,30匹配到10。这样就得到了高对比度图像
在这里插入图片描述


LUT函数

void LUT(InputArray src, InputArray lut, OutputArray dst)
Parameters: 
第一个参数:原始图像的地址; 
第二个参数:查找表的地址,对于多通道图像的查找,它可以有一个通道,也可以与原始图像有相同的通道; 
第三个参数:输出图像的地址。

LUT应用

  1. 颜色空间缩减
    将现有颜色空间值除以某个输入值,以获得较少的颜色数。例如,颜色值0到9可取为新值0,10到19可取为10,以此类推。(示例来源于OpenCV官网)。

    显然这是一个多对一的映射,I[new] = I[old]/10*10。很容易想到,只要遍历图像矩阵的每一个像素,对像素应用上述公式就可以完成任务。只是这里用到了除法和乘法运算,而这两种运算又特别费时。鉴于一幅图像只涉及256个像素,我们大可开一个长度为256的数组,让其下标代表旧像素值,数组值代表新的像素值,如lookup[256]={0,…,0,10,…,10,20,…,20,…,250,…,250}。这样我们遍历修改时不就可以通过像素值从表中查出要改变的像素值了么,而且这一过程只有赋值运算。

  2. 图像反转
    显然这是一个一对一的映射,即像素值0变为255,1变为254,2变成253······255变为0,254变成1,253变成2。对应的查找表为lookup[256]={255,254,…,1,0}。

    void Invert(Mat &img,const uchar* const lookup) {
    	for (int i = 0; i < img.rows; i++)
    	{
    		uchar* p = img.ptr<uchar>(i);
    		for (int j = 0; j < img.cols; j++)
    		{
    			p[j] = lookup[p[j]];
    		}
    	}
    }
    int main() {
    	Mat src = imread("D:/test/11.jpeg");
    	imshow("src", src);
    
    
    	Mat img1;
    	cvtColor(src, img1, COLOR_RGB2GRAY);
    	imshow("img1", img1);
    
    	uchar lut[256];
    	for (int i = 0; i < 255; i++)
    	{
    		lut[i] = 255 - i;
    	}
    
    	Invert(img1,lut );
    	imshow("img2", img1);
    	waitKey(0);
    	return 0;
    
    }
    
    Mat lookUpTable(1, 256, CV_8U);
    uchar* p = lookUpTable.data;
    for (int i = 0; i < 256; i++)
    	p[i] = 255 - i;
    //通过LUT函数实现图像取反
    LUT(img1, lookUpTable, img1);
    

    在这里插入图片描述


applyColorMap函数

OpenCV的applyColorMap函数内置了十几种伪彩色替换的LUT。
在这里插入图片描述

相关内容:
谈OpenCV中查询表lookup table的LUT函数

2015-12-04 00:10:00 djmm2012 阅读数 11

参考Opencv 2计算机视觉编程手册

提高对比度方法一:使用查找表修改图像外观

739642-20151203235416783-1737889353.png

可以很方便的实现一些想要的变化:
例如,针对一些图像暗部细节多的情况,设计一个查找表,将暗部细节分配更多的色彩空间,使得其细节显示更加明显。

下图为负片效果:
739642-20151203235947861-1378933044.png

有些图片效果不好的一个原因是因为没有充分利用0-255之间所有的色彩空间,所有,我们可以拉伸图像所覆盖的色彩空间来提升图像展现的效果。
739642-20151204000118627-1321265476.png

同时,在拉伸图像所占色彩空间的同时,我们可以再舍弃一部分两端所占像素比较少的色块。采用此种方式的实现含义,就是再把两端那些少的那些像素剔除掉,设置成0和255。
739642-20151204000147455-1427935301.png

思考:采用此种方式,略过于暴力,可以采用比较柔和的变换(如下图)此图的效果是减少很暗和很亮的图像细节,增加中部颜色的图像细节。

739642-20151204000342986-64788943.png

第一幅为原图,第二幅为右图为经过拉伸的直方图。
739642-20151204000420705-1615728192.png
739642-20151204000427564-989886308.png

提高对比度方法二:直方图均衡化

739642-20151204000650533-774229404.png

提示:
直方图均衡化的思想如图所示,就是使得整个图像在颜色空间(0-255)所占的比例相等。
下图展示在理想连续状态下,直方图均衡化后的效果。

739642-20151204000750596-1001691641.png

但是这是针对连续情况来说的,在实际的计算机中,色彩都不是连续的,都是离散的数字来表示的。所以,我们可以计算简化:

以下建议查看Wiki的链接:其中的例子非常好的说明了情况。

直方图均衡化

转载于:https://www.cnblogs.com/FightForFreedom/p/5018128.html

图像LUT

阅读数 5293

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