实验四 图像艺术化处理实验
实验项目名称:图像艺术化处理实验
实验项目性质:设计性实验
所属课程名称:数字图像分析与艺术化处理
实验计划学时:2
一、实验目的
(2) 掌握各种艺术化处理方法的实现过程。
二.实验内容和要求
编程实现艺术化效果,三类效果中每类至少实现两种。
三.实验主要仪器设备和材料
计算机, VS+openCV
四.实验原理与实验步骤
1.艺术化效果
(1)黑白照片制作
我们通常说的黑白照片并不是数字图像中的二值图,而是灰度图。由彩色图像转化为灰度图像的过程叫做灰度化处理。一般情况下彩色图像每个像素用3个字节表示,每个字节对应着R、G、B分量的亮度(红、绿、蓝),转换后的灰度图像的灰度值在0~255之间,数值越大,该点越白,即越亮,越小则越黑。转换关系为:
编辑
其中Gray(i,j)为转换后的灰度图像在(i,j)点处的灰度值。
灰度图只能表现256种颜色,灰度化处理还有其他的方法,如:取3个分量的最大值、最小值、算术平均值等,目的都是使颜色的R、G、B分量值相等。
(2)染色效果处理
染色效果在数字图像处理中又叫伪彩色处理,即把整幅图像染成一种给定的色调。方法是指定一种渲染颜色,然后用当前像素的灰度分别乘以指定颜色的R、G、B三分量,并将结果作为当前像素的最终颜色。
编辑
(3)怀旧效果处理
怀旧效果一般用在一些相片处理上,使整张相片呈棕褐色,仿佛相片已保存很久,已经发黄。方法是对每个像素的RGB分量按照公式(4-2)赋值:
编辑
2. 风格化效果
(1)马赛克处理
马赛克效果,其原理是将图像划分为很多小块(5*5),在每块内的各个像素都取到相同的红、绿、蓝颜色值,如块内任意一像素的值。从而对某些细节进行模糊化处理,使图像具有马赛克效果。
(2)浮雕处理
浮雕效果针对灰度图像处理,就是只将图像的变化部分突出出来,而相同灰度部分则被淡化,使图像出现纵深感,从而达到浮雕效果。将要处理的像素取值为与前一个相邻像素间的差值,这样灰度平淡区因差值几乎为零则变成黑色,可以通过加上一个常量来增加一些亮度。
编辑
其中,G(i,j)为处理后图像的像素值,f(i,j)为原图像的像素值,f(i-1,j)为前一个相邻像素的值,常量通常取值为128。
(3)霓虹处理
霓虹效果用来描绘图像的轮廓,勾画颜色变化的边缘,产生轮廓发光的效果。先计算原图像当前像素f(i,j)的红、绿、蓝分量与其相同行f(i+1,j)及相同列f(i,j+1)相邻像素的梯度,即差的平方和的平方根,然后将梯度值作为处理后像素g(i,j)的红、绿、蓝的3个分量。
编辑
上式中r1,g1,b1分别为原图像像素f(i,j)的红、绿、蓝分量值,r2,g2,b2分别为原图像同行相邻像素f(i+1,j)的红、绿、蓝分量值,r3,g3,b3分别为原图像同列相邻像素f(i,j+1)的红、绿、蓝分量值,Red,Green,Blue为图像处理后的像素f(i,j)的红、绿、蓝分量值。
(4)素描效果处理
生成近似素描效果的图像有很多种方法,借助拉普拉斯算子生成素描图的方法较为简单。理想的素描图像要求轮廓清晰,线条柔和,且不能包含过多的杂点干扰。拉普拉斯边缘检测得到的正边缘通常可以较好地描述图形的轮廓线条,但往往包含过多的细节信息或受杂点影响,因此需要对边缘检测结果进行进一步处理。首先使用卷积模板消除大量杂点,然后通过设定阈值消除剩余的少量灰度较低的斑点,最后对得到的素描图进行模糊处理,依然使用卷积模板。
实现步骤:
(1)读取图像文件。
(2)对图像利用拉普拉斯算子进行边缘检测,采用卷积模板的方法。模板如图(a)所示。
(3)去除杂点,同样使用卷积模板的方法。对每个像素分别使用两个模板(如图(b)所示)进行卷积运算,对两个结果取较大值,与阈值(一般设为25)比较,小于阈值的点即为杂点。
(4)去除杂点后,图像仍然含有少量灰度较低的斑点,通过设定灰度阈值Ka(一般设为32)去除。方法为:对每个像素的灰度值乘以2,如果灰度值大于255,则设为255;如果小于阈值Ka,则设为0。
(5)对素描图进行模糊处理,卷积模板如图(c)所示。
(6)对图像取反操作,显示处理后的图像。
编辑
3. 扭曲效果处理
扭曲效果包括挤压效果、球面效果、漩涡效果、波浪效果和摩尔纹效果。
挤压效果是将图像向内挤压,产生收缩变形。挤压效果的实现可以看成是数学极坐标的一种体现,将当前像素点、图像正中心点和过中心点的水平线这三要素画出一个极坐标,然后根据用户指定的挤压度,在当前点与中心点所连的直线上映射出一个像素点,最后将这个像素点作为目标点输出。设原图像上的点坐标用(x’,y’)表示,挤压效果图上的点坐标用(x,y)表示,图像正中心点坐标为(midx,midy),ρ和θ表示点(x,y)所在极坐标系对应的极值和极角,degree为挤压度,取值为[1,32],那么挤压效果满足的关系如下式所示:
编辑
球面效果是将图像中部隆起成球形,使对象具有立体凸起效果,就像哈哈镜中的图像一样。其实现类同于挤压效果,也可以看成是极坐标的一种体现。设坐标表示和挤压效果一致,那么球面效果满足的关系如式(4-6)所示:
编辑
漩涡效果是将整幅图像由外向内进行选择扭曲,越往中心,旋转扭曲程度越强烈,从而达到一种很真实的漩涡效果。漩涡效果仍然是极坐标的一种体现,坐标表示和挤压效果一致,不同的是用swirldegree表示漩涡幅度,取值范围为[0.001,0.1],那么该效果满足的关系如式(4-7)所示:
编辑
波浪效果是将图像中的像素产生移位,从而创建出起伏跌荡的图像效果。波浪效果的实现可以理解为某一个像素在它自身一定范围内进行有规律的振动起伏,振动幅度由用户指定,可利用三角函数实现。仍然设原图像上的点坐标用(x’,y’)表示,波浪效果图上的点坐标用(x,y)表示,degree表示振动幅度,取值范围为[1,32],那么该效果满足的关系如式(4-8)所示:
编辑
摩尔纹是大屏幕显示器在显示大面积相同色彩的画面时出现的彩色波浪状条纹,它会影响视觉效果,其实现也可以看成是极坐标的一种体现,但是由于通常情况下得到的摩尔纹效果十分抽象,往往将处理后的图像与原图像进行Alpha混合。设坐标表示与挤压效果一致,degree表示强度,取值范围在[1,16],则摩尔纹效果满足的关系如式(4-9)所示:
编辑
五、实验代码
#include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; //怀旧 Mat OldStyle(Mat src) { Mat output(src.size(), CV_8UC3); for (int i = 0; i < src.rows; i++) { for (int j = 0; j < src.cols; j++) { float R = src.at<Vec3b>(i, j)[2] * 0.393 + src.at<Vec3b>(i, j)[1] * 0.769 + src.at<Vec3b>(i, j)[0] * 0.189; float G = src.at<Vec3b>(i, j)[2] * 0.349 + src.at<Vec3b>(i, j)[1] * 0.686 + src.at<Vec3b>(i, j)[0] * 0.168; float B = src.at<Vec3b>(i, j)[2] * 0.272 + src.at<Vec3b>(i, j)[1] * 0.534 + src.at<Vec3b>(i, j)[0] * 0.131; //防止某个颜色分量的值溢出 R = R > 255 ? 255 : R; G = G > 255 ? 255 : G; B = B > 255 ? 255 : B; output.at<Vec3b>(i, j)[2] = R; //R output.at<Vec3b>(i, j)[1] = G; //G output.at<Vec3b>(i, j)[0] = B; //B } } return output; } //马赛克 // Mat Mosaic(Mat src, int rectangleLenth) { Mat output(src.size(), CV_8UC3); //取中心的像素值 for (int i = 0; i < src.rows; i += rectangleLenth) { for (int j = 0; j < src.cols; j += rectangleLenth) { //对矩形区域内的每一个像素值进行遍历 for (int k = i; k < rectangleLenth + i && k < src.rows; k++) { for (int m = j; m < rectangleLenth + j && m < src.cols; m++) { //在这里进行颜色的修改 output.at<Vec3b>(k, m)[0] = src.at<Vec3b>(i + rectangleLenth / 2, j + rectangleLenth / 2)[0]; output.at<Vec3b>(k, m)[1] = src.at<Vec3b>(i + rectangleLenth / 2, j + rectangleLenth / 2)[1]; output.at<Vec3b>(k, m)[2] = src.at<Vec3b>(i + rectangleLenth / 2, j + rectangleLenth / 2)[2]; } } } } return output; } //霓虹 Mat Neon(Mat src) { //针对灰度图像处理 Mat output(src.size(), CV_8UC3); for (int i = 1; i < src.rows - 1; i++) { for (int j = 1; j < src.cols - 1; j++) { int r1, r2, r3, g1, g2, g3, b1, b2, b3; r1 = src.at<Vec3b>(i, j)[2]; r2 = src.at<Vec3b>(i + 1, j)[2]; r3 = src.at<Vec3b>(i, j + 1)[2]; g1 = src.at<Vec3b>(i, j)[1]; g2 = src.at<Vec3b>(i + 1, j)[1]; g3 = src.at<Vec3b>(i, j + 1)[1]; b1 = src.at<Vec3b>(i, j)[0]; b2 = src.at<Vec3b>(i, j + 1)[0]; b3 = src.at<Vec3b>(i, j + 1)[0]; double R1, R2, G1, G2, B1, B2; R1 = pow(r1 - r2, 2); R2 = pow(r1 - r3, 2); G1 = pow(g1 - g2, 2); G2 = pow(g1 - g3, 2); B1 = pow(b1 - b2, 2); B2 = pow(b1 - b3, 2); double Red, Green, Blue; Red = 2 * sqrt(R1 + R2); Green = 2 * sqrt(G1 + G2); Blue = 2 * sqrt(B1 + B2); Red = Red > 255 ? 255 : Red; Green = Green > 255 ? 255 : Green; Blue = Blue > 255 ? 255 : Blue; Red = Red < 0 ? 0 : Red; Green = Green < 0 ? 0 : Green; Blue = Blue < 0 ? 0 : Blue; output.at<Vec3b>(i, j)[2] = (int)Red; output.at<Vec3b>(i, j)[1] = (int)Green; output.at<Vec3b>(i, j)[0] = (int)Blue; } } return output; } //球面效果 Mat Extrusion(Mat& src, int degree) { assert(degree >= 1 && degree <= 32); Mat output(src.size(), CV_8UC3); int width = output.cols; int heigh = output.rows; Point center(width / 2, heigh / 2); for (int y = 0; y < heigh; y++) { uchar* img_p = output.ptr<uchar>(y); for (int x = 0; x < width; x++) { Point offset(x - center.x, y - center.y); double theta = atan2((double)offset.y, (double)offset.x); double rou = sqrt(pow((double)offset.x, 2) + pow((double)offset.y, 2)); //具体计算方式根据不同的效果进行修改既可 //***计算修改区结束 /*int newX = center.x + int(degree * sqrt(rou) * cos(theta)); int newY = center.y + int(degree * sqrt(rou) * sin(theta));*/ //球面效果/哈哈镜 int newX = center.x + (int)(pow(rou, 2) / max(center.x, center.y) * cos(theta)); int newY = center.y + (int)(pow(rou, 2) / max(center.x, center.y) * sin(theta)); //***计算修改区结束 if (newX < 0) newX = 0; else if (newX >= width) newX = width - 1; if (newY < 0) newY = 0; else if (newY >= heigh) newY = heigh - 1; img_p[3 * x] = src.at<uchar>(newY, newX * 3); img_p[3 * x + 1] = src.at<uchar>(newY, newX * 3 + 1); img_p[3 * x + 2] = src.at<uchar>(newY, newX * 3 + 2); } } return output; } void main() { Mat img = imread("A1.bmp"); int height = img.rows; int width = img.cols; Mat grayImg; cvtColor(img, grayImg, COLOR_BGR2GRAY); Mat result1, result2, result3, result4; result1.create(img.rows, img.cols, CV_8UC1);//黑白 result2.create(grayImg.rows, grayImg.cols, grayImg.type());//浮雕 result3.create(grayImg.size(), img.type());//扭曲挤压 result4.create(img.size(), CV_8UC3);//染色 //黑白照片 for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { result1.at<uchar>(j, i) = 0.11 * img.at<cv::Vec3b>(j, i)[2] + 0.59 * img.at<cv::Vec3b>(j, i)[1] + 0.3 * img.at<cv::Vec3b>(j, i)[0]; } } //浮雕处理 for (int j = 1; j < height; j++) { for (int i = 1; i < width; i++) { float temp; temp = grayImg.at<uchar>(j, i) - grayImg.at<uchar>(j - 1, i - 1) + 128; if (temp < 0 || temp>255) { temp = grayImg.at<uchar>(j, i); } result2.at<uchar>(j, i) = temp; } } //扭曲挤压效果 int midX = width / 2; int midY = height / 2; float offsetX, offsetY, a, r; int X, Y; int degree = 10; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { offsetX = i - midX; offsetY = j - midY; a = atan2((double)offsetY, (double)offsetX); r = sqrtf(sqrtf((float)(offsetX * offsetX + offsetY * offsetY))) * degree; X = (int)(r * cos(a)) + midX; Y = (int)(r * sin(a)) + midY; if (X < 0) X = 0; if (X >= width) X = width - 1; if (Y < 0) Y = 0; if (Y >= height) Y = height - 1; result3.at<Vec3b>(j, i)[0] = img.at<Vec3b>(Y, X)[0]; result3.at<Vec3b>(j, i)[1] = img.at<Vec3b>(Y, X)[1]; result3.at<Vec3b>(j, i)[2] = img.at<Vec3b>(Y, X)[2]; } } //染色处理 for (int j = 1; j < height; j++) { for (int i = 1; i < width; i++) { result4.at<Vec3b>(j, i)[0] = grayImg.at<uchar>(j, i) * 255 / 255; result4.at<Vec3b>(j, i)[1] = grayImg.at<uchar>(j, i) * 245 / 255; result4.at<Vec3b>(j, i)[2] = grayImg.at<uchar>(j, i) * 0 / 255; } } namedWindow("原图"); imshow("原图", img); namedWindow("黑白照片"); imshow("黑白照片", result1); namedWindow("浮雕效果"); imshow("浮雕效果", result2); namedWindow("挤压效果"); imshow("挤压效果", result3); namedWindow("染色效果"); imshow("染色效果", result4); namedWindow("怀旧效果"); imshow("怀旧效果", OldStyle(img)); namedWindow("马赛克效果"); imshow("马赛克效果", Mosaic(img,5)); namedWindow("霓虹效果"); imshow("霓虹效果", Neon(img)); namedWindow("球面效果"); imshow("球面效果", Extrusion(img,10)); waitKey(0); }
六、实验结果
编辑
编辑
编辑
编辑 编辑 编辑
编辑 编辑 编辑
编辑
本次实验每一个图像的艺术化处理,都有对应的关系式,相对来说,算法是固定的,在实验过程中,浮雕效果处理会有一点问题,当时是直接拿原图像直接处理,后来针对实验内容观看发现浮雕效果是针对灰度图像处理,所以使用了cvtColor函数,其他算法出现的效果没有太大问题。通过此次实验了解了各种图像艺术化处理方法的原理,以及实现过程,对本次课程的学习有了很大的帮助。