源地址:http://www.cnblogs.com/easymind223/archive/2012/07/03/2575277.html

 常用Photoshop的玩家都知道Unsharp Mask(USM)锐化,它是一种增强图像边缘的锐化算法,原理在此处,如果你想使用这个算法,强烈推荐看一下。本文进行一下简单的介绍,USM锐化一共分为三步,第一步生成原始图片src的模糊图片和高对比度图片,记为blur和contrast.第二,把src和blur作差,得到一张差分图片,记为diff,它就是下图的UnsharpMask。然后把src和contras按一定的比例相加,这个比例由diff控制,最终得到锐化图片。USM有一个缺点,锐化后最大和最小的像素值会超过原始图片,如下图红色虚线和白色实线所示。

 
代码如下:
  1. void MyTreasureBox::UnsharpMask(const IplImage* src, IplImage* dst, float amount, float radius, uchar threshold, int contrast)
  2. {
  3. if(!src)return ;
  4.  
  5. int imagewidth = src->width;
  6. int imageheight = src->height;
  7. int channel = src->nChannels;
  8.  
  9. IplImage* blurimage = cvCreateImage(cvSize(imagewidth,imageheight), src->depth, channel);
  10. IplImage* DiffImage = cvCreateImage(cvSize(imagewidth,imageheight), 8, channel);
  11.  
  12. //原图的高对比度图像
  13. IplImage* highcontrast = cvCreateImage(cvSize(imagewidth,imageheight), 8, channel);
  14. AdjustContrast(src, highcontrast, contrast);
  15.  
  16. //原图的模糊图像
  17. cvSmooth(src, blurimage, CV_GAUSSIAN, radius);
  18.  
  19. //原图与模糊图作差
  20. for (int y=0; y<imageheight; y++)
  21. {
  22. for (int x=0; x<imagewidth; x++)
  23. {
  24. CvScalar ori = cvGet2D(src, y, x);
  25. CvScalar blur = cvGet2D(blurimage, y, x);
  26. CvScalar val;
  27. val.val[0] = abs(ori.val[0] - blur.val[0]);
  28. val.val[1] = abs(ori.val[1] - blur.val[1]);
  29. val.val[2] = abs(ori.val[2] - blur.val[2]);
  30.  
  31. cvSet2D(DiffImage, y, x, val);
  32. }
  33. }
  34.  
  35. //锐化
  36. for (int y=0; y<imageheight; y++)
  37. {
  38. for (int x=0; x<imagewidth; x++)
  39. {
  40. CvScalar hc = cvGet2D(highcontrast, y, x);
  41. CvScalar diff = cvGet2D(DiffImage, y, x);
  42. CvScalar ori = cvGet2D(src, y, x);
  43. CvScalar val;
  44.  
  45. for (int k=0; k<channel; k++)
  46. {
  47. if (diff.val[k] > threshold)
  48. {
  49. //最终图像 = 原始*(1-r) + 高对比*r
  50. val.val[k] = ori.val[k] *(100-amount) + hc.val[k] *amount;
  51. val.val[k] /= 100;
  52. }
  53. else
  54. {
  55. val.val[k] = ori.val[k];
  56. }
  57. }
  58. cvSet2D(dst, y, x, val);
  59. }
  60. }
  61.  
  62. cvReleaseImage(&blurimage);
  63. cvReleaseImage(&DiffImage);
  64. }

其中用到一个调整图像对比度的函数

  1. void MyTreasureBox::AdjustContrast(const IplImage* src, IplImage* dst, int contrast)
  2. {
  3. if (!src)return ;
  4.  
  5. int imagewidth = src->width;
  6. int imageheight = src->height;
  7. int channel = src->nChannels;
  8.  
  9. //求原图均值
  10. CvScalar mean = {0,0,0,0};
  11. for (int y=0; y<imageheight; y++)
  12. {
  13. for (int x=0; x<imagewidth; x++)
  14. {
  15. CvScalar ori = cvGet2D(src, y, x);
  16. for (int k=0; k<channel; k++)
  17. {
  18. mean.val[k] += ori.val[k];
  19. }
  20. }
  21. }
  22. for (int k=0; k<channel; k++)
  23. {
  24. mean.val[k] /= imagewidth * imageheight;
  25. }
  26.  
  27. //调整对比度
  28. if (contrast <= -255)
  29. {
  30. //当增量等于-255时,是图像对比度的下端极限,此时,图像RGB各分量都等于阀值,图像呈全灰色,灰度图上只有1条线,即阀值灰度;
  31. for (int y=0; y<imageheight; y++)
  32. {
  33. for (int x=0; x<imagewidth; x++)
  34. {
  35. cvSet2D(dst, y, x, mean);
  36. }
  37. }
  38. }
  39. else if(contrast > -255 && contrast <= 0)
  40. {
  41. //(1)nRGB = RGB + (RGB - Threshold) * Contrast / 255
  42. // 当增量大于-255且小于0时,直接用上面的公式计算图像像素各分量
  43. //公式中,nRGB表示调整后的R、G、B分量,RGB表示原图R、G、B分量,Threshold为给定的阀值,Contrast为处理过的对比度增量。
  44. for (int y=0; y<imageheight; y++)
  45. {
  46. for (int x=0; x<imagewidth; x++)
  47. {
  48. CvScalar nRGB;
  49. CvScalar ori = cvGet2D(src, y, x);
  50. for (int k=0; k<channel; k++)
  51. {
  52. nRGB.val[k] = ori.val[k] + (ori.val[k] - mean.val[k]) *contrast /255;
  53. }
  54. cvSet2D(dst, y, x, nRGB);
  55. }
  56. }
  57. }
  58. else if(contrast >0 && contrast <255)
  59. {
  60. //当增量大于0且小于255时,则先按下面公式(2)处理增量,然后再按上面公式(1)计算对比度:
  61. //(2)、nContrast = 255 * 255 / (255 - Contrast) - 255
  62. //公式中的nContrast为处理后的对比度增量,Contrast为给定的对比度增量。
  63.  
  64. CvScalar nRGB;
  65. int nContrast = 255 *255 /(255 - contrast) - 255;
  66.  
  67. for (int y=0; y<imageheight; y++)
  68. {
  69. for (int x=0; x<imagewidth; x++)
  70. {
  71. CvScalar ori = cvGet2D(src, y, x);
  72. for (int k=0; k<channel; k++)
  73. {
  74. nRGB.val[k] = ori.val[k] + (ori.val[k] - mean.val[k]) *nContrast /255;
  75. }
  76. cvSet2D(dst, y, x, nRGB);
  77. }
  78. }
  79. }
  80. else
  81. {
  82. //当增量等于 255时,是图像对比度的上端极限,实际等于设置图像阀值,图像由最多八种颜色组成,灰度图上最多8条线,
  83. //即红、黄、绿、青、蓝、紫及黑与白;
  84. for (int y=0; y<imageheight; y++)
  85. {
  86. for (int x=0; x<imagewidth; x++)
  87. {
  88. CvScalar rgb;
  89. CvScalar ori = cvGet2D(src, y, x);
  90. for (int k=0; k<channel; k++)
  91. {
  92. if (ori.val[k] > mean.val[k])
  93. {
  94. rgb.val[k] = 255;
  95. }
  96. else
  97. {
  98. rgb.val[k] = 0;
  99. }
  100. }
  101. cvSet2D(dst, y, x, rgb);
  102. }
  103. }
  104. }
  105. }

USM锐化之openCV实现,附赠调整对比度函数的更多相关文章

  1. OpenCV实现USM锐化与测试

    OpenCV实现USM锐化 [转]http://www.programdevelop.com/4964391/ USM (Unsharp masking) is a common operation ...

  2. C#调用GDI+1.1中的函数实现高斯模糊、USM锐化等经典效果。

    http://www.cnblogs.com/Imageshop/archive/2012/12/13/2815712.html 在GDI+1.1的版本中,MS加入不少新的特性,其中的特效类Effec ...

  3. 【Python】把文件名命名成canlendar.py竟然导致无法使用canlendar模块 附赠2020年月历

    这个bug困扰了我一阵,直到在 http://www.codingke.com/question/15489 找到了解决问题的钥匙,真是没想到居然是这个原因导致的. 下面是出错信息,可以看到只要目录下 ...

  4. 【SQL】靠谱的TRIM函数,附赠过程一枚

    SQL中有LTRIM和RTRIM这两个函数分别用于去除字符串的首.尾空格,缺乏常见的能同时去除首尾的TRIM函数,另外,这俩函数都只对[空格]有效,所以如果首尾是制表符.换行符等等[空白],它们是不处 ...

  5. SSE图像算法优化系列十六:经典USM锐化中的分支判断语句SSE实现的几种方法尝试。

    分支判断的语句一般来说是不太适合进行SSE优化的,因为他会破坏代码的并行性,但是也不是所有的都是这样的,在合适的场景中运用SSE还是能对分支预测进行一定的优化的,我们这里以某一个算法的部分代码为例进行 ...

  6. atitit  opencv apiattilax总结 约500个函数 .xlsx

    atitit  opencv apiattilax总结 约500个函数 .xlsx 1.1. CxCore中文参考手册 1 1.2. 机器学习中文参考手册  knn  svm  1 1.3. CvAu ...

  7. Python: PS 图像调整--对比度调整

    本文用 Python 实现 PS 里的图像调整–对比度调整.具体的算法原理如下: (1).nRGB = RGB + (RGB - Threshold) * Contrast / 255 公式中,nRG ...

  8. opencv:USM锐化

    USM:unsharp mask 对小的细节干扰小,对大的细节进行锐化 Mat dst; Mat blur_image; GaussianBlur(src, blur_image, Size(3, 3 ...

  9. hibernate内部测试题(附赠答案)

    一.选择题(共25题,每题2.5分,选择一项或多项,漏选错选不得分) 1.在Hibernate中,以下关于主键生成器说法错误的是( ). A.increment可以用于类型为long.short或by ...

随机推荐

  1. 使用ant的war任务打包j2ee web项目

    <?xml version="1.0" encoding="UTF-8"?> <project name="antwebprojec ...

  2. 三个API:开启、关闭、关闭线程重定向

    C:\Windows\sysnative\ 这个目录是作什么用的?来源:互联网 责任编辑:小易 时间:2015/11/13 0:17:19用户提出问题:C:\Windows\sysnative\ 这个 ...

  3. c#与java中byte字节的区别及转换方法

    原文:c#与java中byte字节的区别及转换方法 在java中  byte的范围在 [-128,127] 在C#中  byte的范围在 [0,255] 所以 java程序与C#程序 进行数据传输的时 ...

  4. Android 关于网址,电话号码,邮箱的正则表达式-最权威

    需求:判断网址是否合法 今天在写一个项目的时候,需要能够识别网址的功能,首先想到的是正则表达式 但是网址的类型多种多样,网络上各种表达式也一搜一大把,很难知道哪一位大神写的靠谱 发现:TextView ...

  5. 扩展 Windows Azure 运营能力 – 巴西

    今天早些时候,在巴西圣保罗的一个活动上,我宣布了我们将在巴西设立一个 Windows Azure 区域数据中心的计划.我们希望该区域中心可以在 2014 年年初上线,并且我们很高兴地宣布将在未来 4 ...

  6. []: secureCRT连接ubuntu问题- The remote system refused the connection

    secureCRT连接ubuntu问题- The remote system refused the connection http://jxyang.iteye.com/blog/1484915 解 ...

  7. perl use base 代替 @ISA

    packge Mule; use base ("Horse", "donkey"); # 声明一个超类 它是下面东西的缩写: package Mule; BEG ...

  8. boost.xml_parser中文字符问题

    当使用xml_parser进行读xml时,如果遇到中文字符会出现解析错误. 网上有解决方案说使用wptree来实现,但当使用wptree来写xml时也会出错.而使用ptree来写中文时不会出错. 综合 ...

  9. Cppcheck 1.54 C/C++静态代码分析工具

    Cppcheck是一个C/C++代码分析工具,只检测那些编译器通常无法检测到的bug类型.   官方上建议让编译器提供尽量多的警告提示:1.使用Visual C++的话,应使用警告等级4 2.使用GC ...

  10. svn 标示提示

    原来没有遇到过, 突然发现这次写的项目有几个文件时 这个"表示的" ,死活找不到原因,并且提交,改动 都好烦人,还要锁定什么嘛的. 最后最终知道, 这个意思是  文件的状态为 &q ...