基于opencv的相机之特效功能实现(八)

简介

  本篇是对实现图片处理功能:【特效】实现的记录。

素描

实现原理

  首先将图像灰阶化,然后将图像反相,将反相后的图片进行高斯模糊,最后将模糊后的图片和原图片,以颜色减淡方式叠加,达到素描效果。
参考资料:http://blog.csdn.net/matrix_space/article/details/40589411

具体代码

JNIEXPORT void JNICALL Java_com_example_background_MyPicBackGround_croquisBackGround
(JNIEnv* env, jclass obj, jlong imageCroquis, jint value){
    Mat I_invert;  
    Mat I_gau;  
    float delta=0.01;  
    float alpha=0;  
     
    Mat I_dst;
    vector<Mat> channels;
    IplImage tmp1_1, tmp1_2, tmp1_3;
    IplImage tmp2_1, tmp2_2, tmp2_3;
    IplImage tmp3_1, tmp3_2, tmp3_3;
 
    Mat mat = Mat(*((Mat*)imageCroquis));
 
    split(mat, channels);
    tmp2_1 = channels.at(0);
    tmp2_2 = channels.at(1);
    tmp2_3 = channels.at(2);
 
    Mat Image_out(mat.size(), CV_32FC3);
    mat.convertTo(Image_out, CV_32FC3);
    Mat I(mat.size(), CV_32FC1);
    cv::cvtColor(Image_out, I, CV_BGR2GRAY);
    I=I/255.0;
    I_invert=-I+1.0;
    GaussianBlur(I_invert, I_gau, Size(25, 25), 0, 0);
    I_gau=-I_gau+1.0+delta;
 
    cv::divide(I, I_gau, I_dst);  
    I_dst = I_dst * 255.0;
    tmp1_1 = I_dst;
 
    Mat b(mat.size(), CV_32FC1);  
    Mat g(mat.size(), CV_32FC1);  
    Mat r(mat.size(), CV_32FC1);
 
    Mat rgb[]={b,g,r};  
    tmp3_1 = b;
    tmp3_2 = g;
    tmp3_3 = r;
     
    alpha = (float)value / 20.0;
 
    cvAddWeighted(&tmp1_1, alpha, &tmp2_1, (1-alpha), 0, &tmp3_1);
    cvAddWeighted(&tmp1_1, alpha, &tmp2_2, (1-alpha), 0, &tmp3_2);
    cvAddWeighted(&tmp1_1, alpha, &tmp2_3, (1-alpha), 0, &tmp3_3);
    cv::merge(rgb, 3, Image_out);
    Image_out.convertTo(mat, CV_8UC3);
}

  需要注意下,拖动条传入数据value会影响原图像和素面图像叠加的权重。

效果演示

  对应的效果图片如下:
            
         原图像                                             素描
          

老照片效果

实现原理

  根据转换公式:
          
参考文档:1、http://blog.csdn.net/yangtrees/article/details/9116337
          2、http://blog.csdn.net/matrix_space/article/details/40432125

具体代码

JNIEXPORT void JNICALL Java_com_example_background_MyPicBackGround_oldBackGround
(JNIEnv* env, jclass obj, jlong imageOld, jint value){
    float alpha=0;  
    IplImage tmp1_1, tmp1_2, tmp1_3;
    IplImage tmp2_1, tmp2_2, tmp2_3;
 
    Mat Image_in = Mat(*((Mat*)imageOld));
    Mat Image_out(Image_in.size(), CV_32FC3);  
 
    Mat Image_2(Image_in.size(), CV_32FC3);  
    Image_in.convertTo(Image_2, CV_32FC3);  
 
    Mat r(Image_in.size(), CV_32FC1);  
    Mat g(Image_in.size(), CV_32FC1);  
    Mat b(Image_in.size(), CV_32FC1);  
 
    Mat out[]={b, g, r};  
    split(Image_2, out);  
    tmp1_1 = b;
    tmp1_2 = g;
    tmp1_3 = r;
     
    Mat r_new(Image_in.size(), CV_32FC1);  
    Mat g_new(Image_in.size(), CV_32FC1);  
    Mat b_new(Image_in.size(), CV_32FC1);  
 
    r_new=0.393*r+0.769*g+0.189*b;  
    g_new=0.349*r+0.686*g+0.168*b;  
    b_new=0.272*r+0.534*g+0.131*b;  
 
    Mat rgb[]={b_new, g_new, r_new};  
 
    tmp2_1 = b_new;
    tmp2_2 = g_new;
    tmp2_3 = r_new;
 
    alpha = (float)value / 20.0;
 
    cvAddWeighted(&tmp2_1, alpha, &tmp1_1, (1-alpha), 0, &tmp2_1);
    cvAddWeighted(&tmp2_1, alpha, &tmp1_2, (1-alpha), 0, &tmp2_2);
    cvAddWeighted(&tmp2_1, alpha, &tmp1_3, (1-alpha), 0, &tmp2_3);
 
    merge(rgb, 3, Image_out);
    Image_out.convertTo(Image_in, CV_8UC3);
}

效果演示

  对应的效果图片如下:
             
         原图像                                          老照片效果

浮雕效果

实现原理

  浮雕效果是对图像像素点进行卷积操作。
可以参考文档:1、http://blog.csdn.net/yangtrees/article/details/9090607
              2、http://blog.csdn.net/matrix_space/article/details/40431061

具体代码

JNIEXPORT void JNICALL Java_com_example_background_MyPicBackGround_embossBackGround
(JNIEnv* env, jclass obj, jlong imageEmboss, jint value){
    Mat kernel;  
    Point anchor;  
    double delta;  
    int ddepth;  
    int kernel_size;  
    IplImage tmp1_1, tmp1_2, tmp1_3;
    float alpha = 0.5;
 
    ddepth=-1;  
    anchor=Point(-1,-1);  
    delta=0;  
    kernel_size=3;  
    Mat K_1;  
    float p;  
    p=3;  
 
    K_1=Mat::zeros(kernel_size, kernel_size, CV_32F);
    K_1.at<float>(0,2)=p;  
    K_1.at<float>(2,0)=-p;  
 
    Mat Image_in = Mat(*((Mat*)imageEmboss));
    tmp1_1 = Image_in;
 
    Mat Image_out(Image_in.size(), CV_32FC3);  
    Image_in.convertTo(Image_out, CV_32FC3);  
    tmp1_3 = Image_out;
 
    Mat Image_2(Image_in.size(), CV_32FC3);  
    Image_in.convertTo( Image_2, CV_32FC3);  
    Mat Image_x(Image_in.size(), CV_32FC3);  
 
    cv::filter2D(Image_2, Image_x, ddepth, K_1);  
    cv::add(Image_x, Scalar(128.0, 128.0, 128.0), Image_x);
    tmp1_2 = Image_x;
 
    alpha = (float)value / 20.0;
    cvAddWeighted(&tmp1_2, alpha, &tmp1_1, (1-alpha), 0, &tmp1_3);
 
    Image_out.convertTo(Image_in, CV_8UC3);
}

效果演示

  对应的效果图片如下:
            
         原图像                                        浮雕效果

卡通效果

实现原理

  首先将原图像灰阶、滤波之后,使用Laplacian进行边缘检测,接着对检测结果二值化处理。同时对原图像进行双边滤波处理。最后将二值化图像和双边滤波后图像叠加,形成卡通图像。
  参考资料:http://www.it165.net/pro/html/201503/36347.html

具体代码

JNIEXPORT void JNICALL Java_com_example_background_MyPicBackGround_cartoonBackGround
    (JNIEnv* env, jclass obj, jlong imageCartoon, jint value){
    IplImage tmp_1, tmp_2;
    float alpha = 0;
    Mat Image_in = Mat(*((Mat*)imageCartoon));
    tmp_1 = Image_in;
    Mat Image_out(Image_in.size(), CV_8UC3);
    Mat mask(Image_in.size(), CV_8UC1);  
 
    cv::Mat edge;
    cv::Mat grayImage;
    cv::cvtColor(Image_in, grayImage, CV_BGR2GRAY);
 
    cv::medianBlur(grayImage, grayImage, 7);
    cv::Laplacian(grayImage, edge, CV_8U, 5);
 
    cv::threshold(edge, mask, 80, 255, cv::THRESH_BINARY_INV);
 
    cv::Size size = Image_in.size();
    cv::Size reduceSize;
    reduceSize.width = size.width / 2;
    reduceSize.height = size.height / 2;
    cv::Mat reduceImage = cv::Mat(reduceSize, CV_8UC3);
 
    cv::resize(Image_in, reduceImage, reduceSize);
 
    cv::Mat tmp = cv::Mat(reduceSize, CV_8UC3);
    int repetitions = 7;
    for (int i=0 ; i < repetitions; i++)
    {
        int kernelSize = 9;
        double sigmaColor = 9;
        double sigmaSpace = 7;
        cv::bilateralFilter(reduceImage, tmp, kernelSize, sigmaColor, sigmaSpace);
        cv::bilateralFilter(tmp, reduceImage, kernelSize, sigmaColor, sigmaSpace);
    }
 
    cv::Mat magnifyImage;
    cv::resize(reduceImage, magnifyImage, size);
 
    Image_out.setTo(0); 
    magnifyImage.copyTo(Image_out, mask);
    tmp_2 = Image_out;
 
    alpha = (float)value / 20.0;
    cvAddWeighted(&tmp_2, alpha, &tmp_1, (1-alpha), 0, &tmp_2); 
 
    Image_out.convertTo(Image_in, CV_8UC3);
}

效果演示

  对应的效果图片如下:
           
         原图像                                       卡通效果

渐变效果

实现原理

  以图像某个点为中心,设置它的亮度权重为1,离该中心越远的像素,亮度权重越低。最终形成中心到四周亮度渐变的效果。

具体代码

JNIEXPORT void JNICALL Java_com_example_background_MyPicBackGround_rampBackGround
    (JNIEnv* env, jclass obj, jlong imageRamp, jint value, jint newTouch_x, jint newTouch_y, jint screenHeight, jint screenWidth){
    int width,height;
    int i, j;
    float sum = 0, sum_tmp[2];
    float alpha = 0;
    Mat Image_in = Mat(*((Mat*)imageRamp));
    width = Image_in.rows;
    height = Image_in.cols;
    CvScalar s1;
 
    Mat Image_out(Image_in.size(), CV_32FC3);  
    Image_in.convertTo(Image_out, CV_32FC3);  
 
    Mat Image_2(Image_in.size(), CV_32FC3);  
    Image_in.convertTo(Image_2, CV_32FC3);  
 
    Mat Map(Image_in.size(), CV_32FC3);  
    Mat temp;  
    float val;  
    IplImage tmp_1, tmp_2;
    int touch_y = height * newTouch_x / screenHeight;
    int touch_x = width * newTouch_y / screenWidth;
 
    if((width - touch_x) > touch_x){
        sum_tmp[0] = (width - touch_x) * (width - touch_x);
    }else{
        sum_tmp[0] = touch_x * touch_x;
    }
    if((height - touch_y) > touch_y){
        sum_tmp[1] = (height - touch_y) * (height - touch_y);
    }else{
        sum_tmp[1] = touch_y * touch_y;
    }
     
    sum = std::sqrt(sum_tmp[0] + sum_tmp[1]);
 
    tmp_1 = Map;
    for(i = 0; i < height; i++){
        for(j= 0; j< width; j++){
            sum_tmp[0] = std::abs(i - touch_y) * std::abs(i - touch_y);
            sum_tmp[1] = std::abs(j - touch_x) * std::abs(j - touch_x);
 
            val =1 - (std::sqrt(sum_tmp[0] + sum_tmp[1]) / sum);
            val = val * val * val * val;
            s1.val[0] = val;
            s1.val[1] = val;
            s1.val[2] = val;
            s1.val[3] = val;
            cvSet2D(&tmp_1, j, i, s1);
        }
    }
    cv::multiply(Image_2, Map, Image_out);  
    tmp_1 = Image_out;
    tmp_2 = Image_in;
 
 
    alpha = (float)value / 20.0;
    cvAddWeighted(&tmp_1, alpha, &tmp_2, (1-alpha), 0, &tmp_1);
 
    Image_out.convertTo(Image_in, CV_8UC3);
}


   函数中,传入参数newTouch_x,newTouch_y为界面上图像点击点坐标,也就是渐变效果的中心位置。传入参数value为拖动条数据,也就是最后渐变效果的叠加权重。

  之前有说到以渐变中心点的亮度权重为1,向四周减小。这里将每个像素点对应亮度权重都保存在新建的图像Map中。接着将原图像和亮度权重通过
cv::multiply相乘,得到渐变结果保存在Image_out中。最后根据拖动条数据计算出来的叠加权重来或得原图像和渐变图像最后叠加输出效果。

效果演示

  对应的效果图片如下:
        
         原图像                                      渐变效果

模糊背景

实现原理

  根据传入的坐标为圆心,拖动条的数据为半径参数的圆为前景,其他为背景,将背景模糊掉。

具体代码

JNIEXPORT void JNICALL Java_com_example_background_MyPicBackGround_blurBackGround
(JNIEnv* env, jclass obj, jlong imageWhiteBlack, jint value, jint newTouch_x, 
 jint newTouch_y, jint screenHeight, jint screenWidth){
 
    IplImage myEdofsrc, myEdofres, myEdofroi, myEdofTmp;
    int myEdofSize = 0, myEdofWidth, myEdofHeight;
    CvScalar myEdofs;
    Mat myEdofMat1, myEdofMat2, myEdofMat3, myEdofMat4;
    int i, j;
 
    myEdofMat1 = Mat(*((Mat*)imageWhiteBlack));
 
    myEdofsrc = myEdofMat1;
    myEdofWidth = myEdofMat1.rows;
    myEdofHeight = myEdofMat1.cols;
 
    int touch_y = myEdofHeight * newTouch_x / screenHeight;
    int touch_x = myEdofWidth * newTouch_y / screenWidth;
 
    myEdofSize = myEdofHeight * (value + 4)/ 40;
    myEdofMat2 = Mat(myEdofWidth, myEdofHeight, CV_8UC3, cv::Scalar(0, 0, 0));
    myEdofMat3 = Mat(myEdofWidth, myEdofHeight, CV_8UC3, cv::Scalar(0, 0, 0));
    myEdofMat4 = Mat(myEdofWidth, myEdofHeight, CV_8UC1);
 
    myEdofTmp = myEdofMat2;
    myEdofres = myEdofMat3;
    myEdofroi = myEdofMat4;
    cvZero(&myEdofroi);
 
    for(i=0;i<myEdofWidth;i++){
        for(j=0;j<myEdofHeight;j++){
            myEdofs = cvGet2D(&myEdofsrc, i, j);
            cvSet2D(&myEdofTmp, i, j, myEdofs);
        }
    }
    cvCircle(&myEdofroi, cvPoint(touch_y, touch_x), myEdofSize, CV_RGB(255, 255, 255), -1, 8, 0);
    cvAnd(&myEdofTmp, &myEdofTmp, &myEdofres, &myEdofroi);
     
    if(myEdofSize > 0){
        myEdofMat1.copyTo(myEdofMat2);
        myEdofTmp = myEdofMat2;
        myEdofsrc = myEdofMat1;
        cvSmooth(&myEdofsrc, &myEdofsrc, CV_GAUSSIAN, 33, 33);
 
        for(i=0;i<myEdofWidth;i++){
            for(j=0;j<myEdofHeight;j++){  
                myEdofs = cvGet2D(&myEdofres, i, j);  
                if((myEdofs.val[0] != 0) && (myEdofs.val[1] != 0) && (myEdofs.val[2] != 0)){  
                    myEdofs = cvGet2D(&myEdofTmp, i, j);   
                    cvSet2D(&myEdofsrc, i, j, myEdofs);  
                }  
            }  
        }
    }
}

效果演示

  对应的效果图片如下:
                            
            背景模糊图片

黑白背景效果

实现原理

  和模糊背景效果类似,只不过前置是将背景模糊掉,这是是将背景灰阶掉。

具体代码

JNIEXPORT void JNICALL Java_com_example_background_MyPicBackGround_whiteBlackBackGround
(JNIEnv* env, jclass obj, jlong imageWhiteBlack, jint value, jint newTouch_x, 
 jint newTouch_y, jint screenHeight, jint screenWidth){
    int myGrayPartSize = 0, myGrayPartWidth, myGrayPartHeight;
    CvScalar myGrayParts;
    Mat myGrayPartMat1, myGrayPartMat2, myGrayPartMat3, myGrayPartMat4;
    IplImage myGrayPartsrc, myGrayPartres, myGrayPartroi, myGrayPartTmp;
 
    int i, j;
    float grayScale;
 
    myGrayPartMat1 = Mat(*((Mat*)imageWhiteBlack));
    myGrayPartsrc = myGrayPartMat1;
    myGrayPartWidth = myGrayPartMat1.rows;
    myGrayPartHeight = myGrayPartMat1.cols;
 
    int touch_y = myGrayPartHeight * newTouch_x / screenHeight;
    int touch_x = myGrayPartWidth * newTouch_y / screenWidth;
 
    myGrayPartSize = myGrayPartHeight * (value + 4)/ 40;;
    myGrayPartMat2 = Mat(myGrayPartWidth, myGrayPartHeight, CV_8UC3, cv::Scalar(0, 0, 0));
    myGrayPartMat3 = Mat(myGrayPartWidth, myGrayPartHeight, CV_8UC3, cv::Scalar(0, 0, 0));
    myGrayPartMat4 = Mat(myGrayPartWidth, myGrayPartHeight, CV_8UC1);
 
    myGrayPartTmp = myGrayPartMat2;
    myGrayPartres = myGrayPartMat3;
    myGrayPartroi = myGrayPartMat4;
    cvZero(&myGrayPartroi);
 
    for(i=0;i<myGrayPartWidth;i++){
        for(j=0;j<myGrayPartHeight;j++){
            myGrayParts = cvGet2D(&myGrayPartsrc, i, j);
            cvSet2D(&myGrayPartTmp, i, j, myGrayParts);
        }
    }
    cvCircle(&myGrayPartroi, cvPoint(touch_y, touch_x), myGrayPartSize, CV_RGB(255, 255, 255), -1, 8, 0);
    cvAnd(&myGrayPartTmp, &myGrayPartTmp, &myGrayPartres, &myGrayPartroi);
 
    if(myGrayPartSize > 0){      
        myGrayPartsrc = myGrayPartMat1;
 
        cvCvtColor(&myGrayPartsrc, &myGrayPartroi, CV_BGR2GRAY);
        for(i=0;i<myGrayPartWidth;i++){
            for(j=0;j<myGrayPartHeight;j++){  
                myGrayParts = cvGet2D(&myGrayPartres, i, j);  
                if((myGrayParts.val[0] == 0) || (myGrayParts.val[1] == 0) || (myGrayParts.val[2] == 0)){ 
                    myGrayParts = cvGet2D(&myGrayPartroi, i, j);
                    myGrayParts.val[1] = myGrayParts.val[0];
                    myGrayParts.val[2] = myGrayParts.val[0];
                    cvSet2D(&myGrayPartsrc, i, j, myGrayParts);  
                }  
            }  
        }
    }       
}

效果演示

  对应的效果图片如下:
                         
          黑白背景图片
具体演示下载:http://download.csdn.net/detail/u011630458/9261617

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值