#include <stdio.h>
#include <assert.h>
#include <cv.h>
#include <highgui.h>
extern "C"
{
#include "jpeglib.h"
#include <setjmp.h>
}
#define DEBUG 0
#define OUTPUT_IMAGES 1
/*
* Extract the DC terms from the specified component.
*/
IplImage *
extract_dc(j_decompress_ptr cinfo, jvirt_barray_ptr *coeffs, int ci)
{
jpeg_component_info *ci_ptr = &cinfo->comp_info[ci];
CvSize size = cvSize(ci_ptr->width_in_blocks, ci_ptr->height_in_blocks);
IplImage *dc = cvCreateImage(size, IPL_DEPTH_8U, 1);
assert(dc != NULL);
JQUANT_TBL *tbl = ci_ptr->quant_table;
UINT16 dc_quant = tbl->quantval[0];
#if DEBUG
printf("DCT method: %x\n", cinfo->dct_method);
printf
(
"component: %d (%d x %d blocks) sampling: (%d x %d)\n",
ci,
ci_ptr->width_in_blocks,
ci_ptr->height_in_blocks,
ci_ptr->h_samp_factor,
ci_ptr->v_samp_factor
);
printf("quantization table: %d\n", ci);
for (int i = 0; i < DCTSIZE2; ++i)
{
printf("% 4d ", (int)(tbl->quantval[i]));
if ((i + 1) % 8 == 0)
printf("\n");
}
printf("raw DC coefficients:\n");
#endif
JBLOCKARRAY buf =
(cinfo->mem->access_virt_barray)
(
(j_common_ptr)cinfo,
coeffs[ci],
0,
ci_ptr->v_samp_factor,
FALSE
);
for (int sf = 0; (JDIMENSION)sf < ci_ptr->height_in_blocks; ++sf)
{
for (JDIMENSION b = 0; b < ci_ptr->width_in_blocks; ++b)
{
int intensity = 0;
intensity = buf[sf][b][0]*dc_quant/DCTSIZE + 128;
intensity = MAX(0, intensity);
intensity = MIN(255, intensity);
cvSet2D(dc, sf, (int)b, cvScalar(intensity));
#if DEBUG
printf("% 2d ", buf[sf][b][0]);
#endif
}
#if DEBUG
printf("\n");
#endif
}
return dc;
}
IplImage *upscale_chroma(IplImage *quarter, CvSize full_size)
{
IplImage *full = cvCreateImage(full_size, IPL_DEPTH_8U, 1);
cvResize(quarter, full, CV_INTER_NN);
return full;
}
GLOBAL(int)
read_JPEG_file (char * filename, IplImage **dc)
{
/* This struct contains the JPEG decompression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
*/
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
/* More stuff */
FILE * infile; /* source file */
/* In this example we want to open the input file before doing anything else,
* so that the setjmp() error recovery below can assume the file is open.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to read binary files.
*/
if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
return 0;
}
/* Step 1: allocate and initialize JPEG decompression object */
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
jpeg_stdio_src(&cinfo, infile);
/* Step 3: read file parameters with jpeg_read_header() */
(void) jpeg_read_header(&cinfo, TRUE);
/* We can ignore the return value from jpeg_read_header since
* (a) suspension is not possible with the stdio data source, and
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
* See libjpeg.txt for more info.
*/
/* Step 4: set parameters for decompression */
/* In this example, we don't need to change any of the defaults set by
* jpeg_read_header(), so we do nothing here.
*/
jvirt_barray_ptr *coeffs = jpeg_read_coefficients(&cinfo);
IplImage *y = extract_dc(&cinfo, coeffs, 0);
IplImage *cb_q = extract_dc(&cinfo, coeffs, 1);
IplImage *cr_q = extract_dc(&cinfo, coeffs, 2);
IplImage *cb = upscale_chroma(cb_q, cvGetSize(y));
IplImage *cr = upscale_chroma(cr_q, cvGetSize(y));
cvReleaseImage(&cb_q);
cvReleaseImage(&cr_q);
#if OUTPUT_IMAGES
cvSaveImage("y.png", y);
cvSaveImage("cb.png", cb);
cvSaveImage("cr.png", cr);
#endif
*dc = cvCreateImage(cvGetSize(y), IPL_DEPTH_8U, 3);
assert(dc != NULL);
cvMerge(y, cr, cb, NULL, *dc);
cvReleaseImage(&y);
cvReleaseImage(&cb);
cvReleaseImage(&cr);
/* Step 7: Finish decompression */
(void) jpeg_finish_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* Step 8: Release JPEG decompression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 1;
}
int
main(int argc, char **argv)
{
int ret = 0;
if (argc != 2)
{
fprintf(stderr, "usage: %s filename.jpg\n", argv[0]);
return 1;
}
IplImage *dc = NULL;
ret = read_JPEG_file(argv[1], &dc);
assert(dc != NULL);
IplImage *rgb = cvCreateImage(cvGetSize(dc), IPL_DEPTH_8U, 3);
cvCvtColor(dc, rgb, CV_YCrCb2RGB);
#if OUTPUT_IMAGES
cvSaveImage("rgb.png", rgb);
#else
cvNamedWindow("DC", CV_WINDOW_AUTOSIZE);
cvShowImage("DC", rgb);
cvWaitKey(0);
#endif
cvReleaseImage(&dc);
cvReleaseImage(&rgb);
return 0;
}
收集自:Extracting DCT coefficients from encoded images and video
photoshop 中渐变映射的算法跟曲线工具的原理是一样的
可以用调节曲线代替,
替代方法:
比如渐变映射编辑器中的色彩是左边(#001122)右边是#ddeeff
那么曲线对应的方法是:
红色两个控制点,(#0,#0) (#ff,#dd)
绿色两个控制点,(#0,#11) (#ff,#ee)
绿色两个控制点,(#0,#22) (#ff,#ff)
渐变映射的图层模式和透明度调节
效果等同与将复制图层,调节曲线调节后的图层模式和透明度
曲线工具的原理在 camera360的红外热像特效算法 中有说明
转载一篇
“可选颜色”是Adobe Photoshop中的一条关于色彩调整的命令。但与色阶,色彩平衡和色相饱和度相比,就没有那么直观,所以大家常常遇到可选颜色时,并不是那么顺手,我 也在网络上查了查关于可选颜色的教程,但基本上都是些以实例为主的,参数调好了,跟着一调,就OK了,但真正让自己调别的图的时候,又不知如何入手。或者 效果不理想,干脆抛弃了这个很有用的调色工具!
我在这里就简单的给初学的朋友说说怎么调可选颜色好的,我们现在开始进入可选颜色的忽悠话题:如果真的想用好可选颜色,首先应该多了解一下色彩基础知识,否则还是一头雾水!
上面一张图是RGB三原色及其对应色的关系(有助于可选颜色的理解),接下来:我们在PS中画出如下图形(绿色和蓝色图层混合模式改为滤色):
这时候我们打开可选颜色调整对话框(图像》调整》可选颜色),首先调整红色:
看第一个调整色:青色!
青色代表什么呢?大家在RGB三原色及其对应色的关系中可以看出,青色是红色的对应色,如果我们把滑块向右拖动增加青色,红色是不是越来越黑了,那正是两 个对应色混合,相互吸收的原理。拖动滑块向左减少青色,大家看到什么?是不是没有变化呀,因为在红色本色就不具有青色
看第二个调整色:洋红!
红色是由洋红和黄色混合产生,我们这个红色已经是100%的纯红色,所以向右增加洋红,不会改变红色,向左减少洋红,会使红色部分越来越偏黄,降到-100,就变成纯黄色了。
看第三个调整色:黄色!
红色是由洋红和黄色混合产生,我们这个红色已经是100%的纯红色,所以向右增加黄色,不会改变红色,向左减少黄色,会使红色部分越来越偏洋红,降到-100,就变成洋红了。
看第四个调整色:黑色! 这个比较简单,是调整红色的明度,左明右暗。
好了,通过这一个色彩的调整,我们就应该知道其原理了吧,你可以试试别的颜色的调整,来提高对可选颜色的认识!
(另一)
我们以对色彩、亮度的直觉来认识和感知这个世界,却不得不用数字化的方式记录这个世界,我们想以最直观的方法来调整和改变图像,却在一个个似是 而非的概念面前无所适从。对于可选颜色来说,更是如此,作为一个高级色彩调整工具,却长期以来没有被人正确认识。今天我就个人经验,向大家讲解一下这方面 的规律
用可选颜色进行调整前首先要指定一个选择范围,所做的调整只对范围内的像素有效
如图,大致可以分为三组:
以RGB三原色来划分:红色、绿色、蓝色
以三原色的补色CMY来划分:黄色、青色、洋红
上面两组是以色度来划分的
以整体的亮度来划分:白色、黑色、中性色
: O5
如果想从数字角度来了解范围的划分的话,可以参考下图,记得把你的信息调板设为RGB和HSB
当我们选定了一个范围后,可以拖动滑块,分别改变这个范围内像素的三原色数值进行调整,如图,也是利用了色彩平衡的互补色原理,与之不同的是可以单独调整某一个分量,并不会影响到另外两个。同时增加了一个黑色滑块,调整黑色时数值变化等同于同时作用于三个分量。
假定图像中有这么一个像素A(R180,G100,B50),可以知道当选择范围是红色、黄色、中性色的时候调整对其有效.选择范围为红色,方式选绝对。
我们把黑色滑块从0到-100向左拖动,R、G、B的数值不断增加,在某一个部位到达了上限就会停止变化,同样向右拖动时就会到达下限,我们可以把到上限的改变量称之为增加量INC、到下限的改变量称之为减小量DEC,整个的数值可变范围称之为调整总量LIM。
可以看到,在同一个选择范围下,R、G、B的LIM值是相同的,变化幅度的不同表现在INC和DEC的比例不同(LIM=INC+DEC)。
那么选择范围不同会不会对这个可调整总量产生影响呢,答案是肯定的。
当选择范围是红色的时候,R、G、B数值的可变范围取决于它们之间的最大值MAX(rgb)和中间值MID(rgb)之差
对于像素A来说,LIM=180-100=80,这个算式也同样适用于绿色和蓝色。
当选择范围是黄色的时候,R、G、B数值的可变范围取决于它们之间的最小值MIN(rgb)和中间值MID(rgb)之差
对于像素A来说,LIM=100-50=50,这个算式也同样适用于青色和洋红
当选择范围是中性色的时候:
当选择范围是白色的时候,
当选择范围是黑色的时候’
前面说到在同一个选择范围下进行可选颜色调整,R、G、B数值的整体可变范围是相同的,不同的是增加量INC和减小量DEC的比例不同,滑块向右,数值减小,减小量和原色数值成正比。滑块向左,数值增加,增加量和原色数值的反相成正比。
可以用下面的算式来表示
R/255)
1-R/255)
R也可以换成G或者B,具体就看你是在调整哪个色彩分量了。
拿像素A具体来看一下,每个百分比调整的幅度,青色滑块向右,R减小,但是在滑块移动到+70时R值就已经到达下限了,青色滑块向左,R增加,在滑块移动到-30时R值就到达上限,可以看到,在绝对的时候把整个可调整范围拿来百分,每个百分比调整的幅度较大。
相对的情况下则有些不同了,滑块在0到+100之间百分R的减小量,在0到-100之间百分R的增加量,每个百分比调整的幅度较小。所以选择相对的时候调整会更精细一些。
但是只要是把滑块调到头,不管相对还是绝对大多数时候的最终效果是一致的……打个问号,为什么说是大多数时候?
这是因为选择相对的时候,算法和绝对的基本一样,先算出可调整总量,然后根据R、G、B分量的具体数值来确定增加量和减小量,但是如果某个分量大于128,就会对减小量有一个修正,即减小量=增加量。
就HSL的概念来讲,一个像素R、G、B三原色的最大值和最小值决定了它的色彩(色相),比如说像素A表红、表黄,中间值和最大值、最 小值之间的差值则决定了这个色彩的纯度,差值越大,色彩越鲜艳。反过来讲选择色度范围来进行调整时越鲜艳的色彩可调整的幅度越大。但这是否意味着可选颜色 对于接近灰色的像素意义不大呢?不是的,至少我们还可以选择亮度范围来进行调整
可选颜色具有多种选择范围的特性使得我们可以有针对性的对图像进行色彩矫正或者调整,我们可以根据自己的直觉或者经验来选择比如说调整人物肤色 应该选择红色或者黄色,调整天空选择蓝色或青色,调整高光选择白色,调整阴影选择黑色,当然有些直觉并不见得完全正确,这就需要我们具体情况具体分析,这 个分析的基础就是前面所讲的东西.
以上的所做的探讨的仅限于RGB模式,可以用作图像调整的参考。对于CMYK模式的调整,那是属于印前的范畴,对印刷了解不深,俺就不敢在这里妄言了。
来源:http://www.360doc.com/content/10/0130/21/729091_14757276.shtml
gimp 中有一个类似于 photoshop 中high pass filter的插件,查到了作者对算法的描述,很简答,如下:
- 复制图层
- 模糊副本
- 翻转副本
- 设置不透明度50%,图层模式正常
- 合并
效果如下:
参考链接:
http://registry.gimp.org/node/7385
http://www.cartographersguild.com/showthread.php?2582-High-Pass-Filter-in-GIMP-(new-plugin)
http://www.gimp.org/tutorials/Sketch_Effect/
Learning the k in k-means 中介绍了一种简洁的可以自动选取k-means k值得算法 G-means,这个算法是对k-means的封装。这个算法初始时选取一个较小的k值,如果完全没有先验的k值,可以使k=1,运行k-means, 然后对当前每一个聚类结果进行正态分析,如果该类别符合正态分布,该类别就做为一个类别保存,如果不符合正态分布,就在这个类别上运行k-means k=2。如此递归,知道所有的聚类结果都符合正态分布。这也是该算法的假设。G-means 在应用中有不错的表现。
其算法过程如下:
其中如何验证一个聚类是否通过正态分布测试是关键的,文中有详细的描述
reference:
图像/视频检索中一种常用而且易于理解的方法叫做 bag of features,简称BOF。顾名思义,bof是用图像中的特征点信息作为图像的表示来进行检索的。
83年Salton & McGill 提出的一种使用词频来表示无序文档的算法,就是用文档分词后的单词在词典中出现的频率来表示文档,如下图所示
bof的做法是类似的:
- 对图库中的图像提取特征点,比如sift,surf,mser等
- 生成特征点的词典:对特征点进行聚类,k-means会是不错的选择
- 生成图片的BOF:对图片中的特征点,找到其在词典中的分类,然后计算该特征点的tf-idf权重,一张图像中所有特征点的分类和权重,构成了这张图像的BOF表示
- 查询过程是计算出查询图像的bof并跟图库中图像bof距离比较的过程
tf-idf 是term frequency, inverse document frequency的简写,一个特征的tf-idf值反应的该特征对表示这张图像的重要性
tf-idf = tf * idf
其中tf 是该词在该文档中出现的频率,idf是所有文档中出现这个词的频率的倒数
opencv中已经有了相关的算法实现
做这个效果有比较复杂的效果,不过如果要做成实时效果,就必须简化算法
使用这个算子就可以搞定了:
2 0 0
0 -1 0
0 0 -1
按下鼠标左键查看原图:
![]()
![]()
github挺好用的
以后就在github上发布代码了
不知道为什么不用google code管理代码,也许是以前不熟悉google code默认的svn
而现在恰巧在使用git
也许是google code没有统一管理个人项目的页面
我的github地址:https://github.com/zhijie
最新评论