image blur detection

py

# -*-coding=UTF-8-*-
"""
在无参考图下,检测图片质量的方法
"""
import os
import cv2
import ctypes
import sys
import numpy as np
from skimage import filters

def _load_shared_lib(libpath):
    return ctypes.cdll.LoadLibrary(libpath)
    
class BlurDetection:
    def __init__(self, strDir):
        print("图片检测对象已经创建...")
        self.strDir = strDir

    def _getAllImg(self, strType='jpg'):
        """
        根据目录读取所有的图片
        :param strType: 图片的类型
        :return:  图片列表
        """
        names = []
        for root, dirs, files in os.walk(self.strDir):  # 此处有bug  如果调试的数据还放在这里,将会递归的遍历所有文件
            for file in files:
                # if os.path.splitext(file)[1]=='jpg':
                names.append(str(file))
        return names

    def _imageToMatrix(self, image):
        """
        根据名称读取图片对象转化矩阵
        :param strName:
        :return: 返回矩阵
        """
        imgMat = np.matrix(image)
        return imgMat

    def _Tenengrad(self,imgName):
        """
                       灰度方差乘积
                       :param imgName:
                       :return:
                       """
        # step 1 图像的预处理
        # img2gray, reImg = self.preImgOps(imgName)
        # f = self._imageToMatrix(img2gray)

        # tmp = filters.sobel(f)
        # source=np.sum(tmp**2)
        # source=np.sqrt(source)
        imgPath = self.strDir + imgName
        reImg = cv2.imread(imgPath)
        reImg = cv2.resize(reImg, (144,144))

        image_data = np.asarray(reImg, dtype=np.uint8)
        # image_data = reImg
        image_data = image_data.ctypes.data_as(ctypes.c_char_p)
        c_lib.tenengard.argtypes = (ctypes.c_int,ctypes.c_int,ctypes.c_char_p)
        
        c_lib.tenengard.restype = ctypes.c_double
        source = round(c_lib.tenengard(reImg.shape[0], reImg.shape[1], image_data),4)
        # strp3: 绘制图片并保存  不应该写在这里  抽象出来   这是共有的部分

        newImg = self._drawImgFonts(reImg, str(source))
        newDir = self.strDir + "/_Tenengrad_/"
        if not os.path.exists(newDir):
            os.makedirs(newDir)
        newPath = newDir + imgName
        cv2.imwrite(newPath, newImg)  # 保存图片
        # cv2.imshow(imgName, newImg)
        # # cv2.waitKey(0)
        # if cv2.waitKey(10) & 0xff == ord("q"):
        #     # break
        #     cv2.destroyAllWindows()
        return source

    def _blurDetection(self, imgName):

        # step 1 图像的预处理
        # img2gray, reImg = self.preImgOps(imgName)
        # imgMat=self._imageToMatrix(img2gray)/255.0
        # x, y = imgMat.shape
        # score = 0
        # for i in range(x - 2):
        #     for j in range(y - 2):
        #         score += (imgMat[i + 2, j] - imgMat[i, j]) ** 2
        imgPath = self.strDir + imgName
        reImg = cv2.imread(imgPath)
        reImg = cv2.resize(reImg, (144,144))
        # imgPath = ctypes.c_char_p(imgPath.encode('utf-8'))
        image_data = np.asarray(reImg, dtype=np.uint8)
        image_data = image_data.ctypes.data_as(ctypes.c_char_p)
        c_lib.brenner.argtypes = (ctypes.c_int,ctypes.c_int,ctypes.c_char_p)

        c_lib.brenner.restype = ctypes.c_double
        score = round(c_lib.brenner(reImg.shape[0], reImg.shape[1], image_data),4)
        # step3: 绘制图片并保存  不应该写在这里  抽象出来   这是共有的部分
        newImg = self._drawImgFonts(reImg, str(score))
        newDir = self.strDir + "/_blurDetection_/"
        if not os.path.exists(newDir):
            os.makedirs(newDir)
        newPath = newDir + imgName
        cv2.imwrite(newPath, newImg)  # 保存图片
        # cv2.imshow(imgName, newImg)
        # cv2.waitKey(0)
        return score

    def _SMD2Detection(self, imgName):
        """
        灰度方差乘积
        :param imgName:
        :return:
        """
        # step 1 图像的预处理
        # img2gray, reImg = self.preImgOps(imgName)
        # f=self._imageToMatrix(img2gray)/255.0
        # x, y = f.shape
        # score = 0
        # for i in range(x - 1):
        #     for j in range(y - 1):
        #         score += np.abs(f[i+1,j]-f[i,j])*np.abs(f[i,j]-f[i,j+1])
        # # strp3: 绘制图片并保存  不应该写在这里  抽象出来   这是共有的部分
        # score=score
        imgPath = self.strDir + imgName
        reImg = cv2.imread(imgPath)
        reImg = cv2.resize(reImg, (144,144))
        # imgPath = ctypes.c_char_p(imgPath.encode('utf-8'))
        image_data = np.asarray(reImg, dtype=np.uint8)
        image_data = image_data.ctypes.data_as(ctypes.c_char_p)
        c_lib.smd2.argtypes = (ctypes.c_int,ctypes.c_int,ctypes.c_char_p)

        c_lib.smd2.restype = ctypes.c_double
        score = round(c_lib.smd2(reImg.shape[0], reImg.shape[1], image_data),4)

        newImg = self._drawImgFonts(reImg, str(score))
        newDir = self.strDir + "/_SMD2Detection_/"
        if not os.path.exists(newDir):
            os.makedirs(newDir)
        newPath = newDir + imgName
        cv2.imwrite(newPath, newImg)  # 保存图片
        # cv2.imshow(imgName, newImg)
        # cv2.waitKey(0)
        return score

    def _Energy_gradient(self, imgName):
        """
               灰度方差乘积
               :param imgName:
               :return:
               """
        # step 1 图像的预处理
        imgPath = self.strDir + imgName
        reImg = cv2.imread(imgPath)
        reImg = cv2.resize(reImg, (144,144))
        # imgPath = ctypes.c_char_p(imgPath.encode('utf-8'))
        image_data = np.asarray(reImg, dtype=np.uint8)
        image_data = image_data.ctypes.data_as(ctypes.c_char_p)
        c_lib.energy_gradient.argtypes = (ctypes.c_int,ctypes.c_int,ctypes.c_char_p)

        c_lib.energy_gradient.restype = ctypes.c_double
        score = round(c_lib.energy_gradient(reImg.shape[0], reImg.shape[1], image_data),4)

        # strp3: 绘制图片并保存  不应该写在这里  抽象出来   这是共有的部分
        newImg = self._drawImgFonts(reImg, str(score))
        newDir = self.strDir + "/_Energy_gradient_/"
        if not os.path.exists(newDir):
            os.makedirs(newDir)
        newPath = newDir + imgName
        cv2.imwrite(newPath, newImg)  # 保存图片
        # cv2.imshow(imgName, newImg)
        # cv2.waitKey(0)
        return score

    def _Nrss(self,imgName):
        """
                       灰度方差乘积
                       :param imgName:
                       :return:
                       """
        # step 1 图像的预处理
        imgPath = self.strDir + imgName
        reImg = cv2.imread(imgPath)
        reImg = cv2.resize(reImg, (144,144))
        # imgPath = ctypes.c_char_p(imgPath.encode('utf-8'))
        image_data = np.asarray(reImg, dtype=np.uint8)
        image_data = image_data.ctypes.data_as(ctypes.c_char_p)
        c_lib.nrss.argtypes = (ctypes.c_int,ctypes.c_int,ctypes.c_char_p)

        c_lib.nrss.restype = ctypes.c_double
        source = round(c_lib.nrss(reImg.shape[0], reImg.shape[1], image_data),4)
        # strp3: 绘制图片并保存  不应该写在这里  抽象出来   这是共有的部分

        newImg = self._drawImgFonts(reImg, str(source))
        newDir = self.strDir + "/_Nrss_/"
        if not os.path.exists(newDir):
            os.makedirs(newDir)
        newPath = newDir + imgName
        cv2.imwrite(newPath, newImg)  # 保存图片
        # cv2.imshow(imgName, newImg)
        # cv2.waitKey(0)
        return source
    
    def preImgOps(self, imgName):
        """
        图像的预处理操作
        :param imgName: 图像的而明朝
        :return: 灰度化和resize之后的图片对象
        """
        strPath = self.strDir + imgName

        img = cv2.imread(strPath)  # 读取图片
        # cv2.moveWindow("", 1000, 100)
        # cv2.imshow("原始图", img)
        # 预处理操作
        reImg = cv2.resize(img, (144, 144), interpolation=cv2.INTER_CUBIC)  #
        h1, w1, _ = reImg.shape
        reImg=reImg[int(h1*0.1):int(h1*0.9), int(w1*0.1):int(w1*0.9), :]
        img2gray = cv2.cvtColor(reImg, cv2.COLOR_BGR2GRAY)  # 将图片压缩为单通道的灰度图
        return img2gray, reImg

    def _drawImgFonts(self, img, strContent):
        """
        绘制图像
        :param img: cv下的图片对象
        :param strContent: 书写的图片内容
        :return:
        """
        font = cv2.FONT_HERSHEY_SIMPLEX
        fontSize = 1
        # 照片 添加的文字    /左上角坐标   字体   字体大小   颜色        字体粗细
        cv2.putText(img, strContent, (5, 50), font, fontSize, (0, 255, 0), 2)

        return img

    def _lapulaseDetection(self, imgName):
        """
        :param strdir: 文件所在的目录
        :param name: 文件名称
        :return: 检测模糊后的分数
        """
        # step1: 预处理
        # img2gray, reImg = self.preImgOps(imgName)
        # # step2: laplacian算子 获取评分
        # resLap = cv2.Laplacian(img2gray, cv2.CV_64F)
        # score = resLap.var()
        imgPath = self.strDir + imgName
        reImg = cv2.imread(imgPath)
        reImg = cv2.resize(reImg, (144,144))
        
        image_data = np.asarray(reImg, dtype=np.uint8)
        # image_data = reImg
        image_data = image_data.ctypes.data_as(ctypes.c_char_p)
        c_lib.laplacian.argtypes = (ctypes.c_int,ctypes.c_int,ctypes.c_char_p)

        c_lib.laplacian.restype = ctypes.c_double
        score = round(c_lib.laplacian(reImg.shape[0], reImg.shape[1], image_data),4)
        print("Laplacian %s score of given image is %s", str(score))
        # strp3: 绘制图片并保存  不应该写在这里  抽象出来   这是共有的部分
        newImg = self._drawImgFonts(reImg, str(score))
        newDir = self.strDir + "/_lapulaseDetection_/"
        if not os.path.exists(newDir):
            os.makedirs(newDir)
        newPath = newDir + imgName
        # 显示
        cv2.imwrite(newPath, newImg)  # 保存图片
        # cv2.imshow(imgName, newImg)
        # cv2.waitKey(0)

        # step3: 返回分数
        return score


    def Test_Tenengrad(self):
        out_file = 'Test_Tenengrad_c_2.txt'
        with open(out_file, 'w') as fout: 
            imgList = self._getAllImg(self.strDir)
            for i in range(len(imgList)):
                score = self._Tenengrad(imgList[i])
                print(str(imgList[i]) + " is " + str(score))

                write_line = '%s\t' % str(imgList[i])
                write_line += '%f\n' % float(score)
                fout.write(write_line)

    def TestBrener(self):
        imgList = self._getAllImg(self.strDir)

        for i in range(len(imgList)):
            score = self._blurDetection(imgList[i])
            print(str(imgList[i]) + " is " + str(score))
        return

    def TestLapulase(self):
        out_file = 'TestLapulase_c_2.txt'
        with open(out_file, 'w') as fout: 
            names = self._getAllImg()
            for i in range(len(names)):
                score = self._lapulaseDetection(names[i])
                print(str(names[i]) + " is " + str(score))
                write_line = '%s\t' % str(names[i])
                write_line += '%f\n' % float(score)
                fout.write(write_line)
        return

    def TestSMD2(self):
        imgList = self._getAllImg(self.strDir)

        for i in range(len(imgList)):
            score = self._SMD2Detection(imgList[i])
            print(str(imgList[i]) + " is " + str(score))
        return

    def Test_EnergyGrad(self):
        imgList = self._getAllImg(self.strDir)
        for i in range(len(imgList)):
            score = self._Energy_gradient(imgList[i])
            print(str(imgList[i]) + " is " + str(score))


    def Test_Nrss(self):
        imgList = self._getAllImg(self.strDir)
        for i in range(len(imgList)):
            score = self._Nrss(imgList[i])
            print(str(imgList[i]) + " is " + str(score))


if __name__ == "__main__":
    # imgpath = str(sys.argv[1])
    # libpath = str(sys.argv[2])
    libpath = 'blur_detection2.so'
    c_lib = _load_shared_lib(libpath)
    BlurDetection = BlurDetection(strDir="save_images3/")
    
    BlurDetection.Test_Tenengrad () # TestSMD
    BlurDetection.TestLapulase() # TestSMD
    # BlurDetection.TestBrener()
    # BlurDetection.TestSMD2()
    # BlurDetection.Test_EnergyGrad()
    # BlurDetection.Test_Nrss()


C++

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <vector>
#include <string>
#include <fstream>

#define FIXED_SIZE 144
#define EDGE_THRESH 35
#define MIN_ZERO 0.05

/**         
* Tenengrad梯度方法 
*   
* Inputs:   
* @param image:  
* Return: double    
*/
extern "C"
{
    double tenengard(int height, int width, uchar* frame_data)
    {
		int count = 0;
        cv::Mat image(height, width, CV_8UC3);
        uchar* pxvec =image.ptr<uchar>(0);
        
        for(int row = 0; row < height; row++)
        {
            pxvec = image.ptr<uchar>(row);
            for(int col = 0; col < width; col++)
            {
                for(int c = 0; c < 3; c++)
                {
                    pxvec[col*3+c] = frame_data[count];
                    count++;
                }
            }
        }
    
        cv::Mat gray_img, sobel_x, sobel_y, G;
        if (image.channels() == 3){
            cv::cvtColor(image, gray_img, CV_BGR2GRAY);
        }
    
        //分别计算x/y方向梯度
        cv::Sobel(gray_img, sobel_x, CV_32FC1, 1, 0);
        cv::Sobel(gray_img, sobel_y, CV_32FC1, 0, 1);
        cv::multiply(sobel_x, sobel_x, sobel_x);
        cv::multiply(sobel_y, sobel_y, sobel_y);
        cv::Mat sqrt_mat = sobel_x + sobel_y;
        cv::sqrt(sqrt_mat, G);

        // std::cout << "tenengard: " <<  cv::mean(G)[0] << std::endl;
        // std::cout << "type: " << typeid(cv::mean(G)[0]).name() << std::endl;
        return cv::mean(G)[0];
    }
}

/**         
* Brenner梯度方法 
*   
* Inputs:   
* @param image:  
* Return: double    
*/
extern "C"
{
    double brenner(int height, int width, uchar* frame_data)
    {
        int count = 0;
        cv::Mat image(height, width, CV_8UC3);
        uchar* pxvec =image.ptr<uchar>(0);
        
        for(int row = 0; row < height; row++)
        {
            pxvec = image.ptr<uchar>(row);
            for(int col = 0; col < width; col++)
            {
                for(int c = 0; c < 3; c++)
                {
                    pxvec[col*3+c] = frame_data[count];
                    count++;
                }
            }
        }
    
        cv::Mat gray_img;
        if (image.channels() == 3){
            cv::cvtColor(image, gray_img, CV_BGR2GRAY);
        }
    
        double result = .0f;
        for (int i = 0; i < gray_img.rows; ++i){
            uchar *data = gray_img.ptr<uchar>(i);
            for (int j = 0; j < gray_img.cols - 2; ++j){
                result += pow(data[j + 2] - data[j], 2);
            }
        }
        // std::cout << "brenner: " << result/gray_img.total() << std::endl;
        return result/gray_img.total();
    }
}



/**         
* Laplacian 梯度函数 
*   
* Inputs:   
* @param image:  
* Return: double    
*/
extern "C"
{
    // double laplacian(cv::Mat &image)
    double laplacian(int height, int width, uchar* frame_data)
    {
        int count = 0;
        cv::Mat image(height, width, CV_8UC3);
        uchar* pxvec =image.ptr<uchar>(0);
        
        for(int row = 0; row < height; row++)
        {
            pxvec = image.ptr<uchar>(row);
            for(int col = 0; col < width; col++)
            {
                for(int c = 0; c < 3; c++)
                {
                    pxvec[col*3+c] = frame_data[count];
                    count++;
                }
            }
        }
        
        cv::Mat gray_img=cv::Mat(image.size(),CV_8UC1);
        cv::Mat lap_image=cv::Mat(image.size(),CV_8UC1);
        if (image.channels() == 3){
            cv::cvtColor(image, gray_img, CV_BGR2GRAY);
            // std::cout << "file_path: " << file_path << std::endl;
			// std::cout << "width: " << image.rows << std::endl;
			// std::cout << "height: " << image.cols << std::endl;
            // std::cout << "img.size: " << image.size() << std::endl;
        }
    
        cv::Laplacian(gray_img, lap_image, CV_32FC1);
        lap_image=cv::abs(lap_image);

        // std::cout << "laplacian: " << cv::mean(lap_image)[0] << std::endl;
    
        return cv::mean(lap_image)[0];
    }
}

/**         
* SMD(灰度方差)函数 
*   
* Inputs:   
* @param image:  
* Return: double    
*/
extern "C"
{
    double smd(cv::Mat &image)
    {
        // assert(image.empty());
    
        cv::Mat gray_img, smd_image_x, smd_image_y, G;
        if (image.channels() == 3){
            cv::cvtColor(image, gray_img, CV_BGR2GRAY);
        }
    
        cv::Mat kernel_x(3, 3, CV_32F, cv::Scalar(0));
        kernel_x.at<float>(1, 2) = -1.0;
        kernel_x.at<float>(1, 1) = 1.0;
        cv::Mat kernel_y(3, 3, CV_32F, cv::Scalar(0));
        kernel_y.at<float>(0, 1) = -1.0;
        kernel_y.at<float>(1, 1) = 1.0;
        cv::filter2D(gray_img, smd_image_x, gray_img.depth(), kernel_x);
        cv::filter2D(gray_img, smd_image_y, gray_img.depth(), kernel_y);
    
        smd_image_x = cv::abs(smd_image_x);
        smd_image_y = cv::abs(smd_image_y);
        G = smd_image_x + smd_image_y;
    
        return cv::mean(G)[0];
    }
}

/**         
* SMD2 (灰度方差乘积)函数
*   
* Inputs:   
* @param image:  
* Return: double    
*/
extern "C"
{
    double smd2(int height, int width, uchar* frame_data)
    {
        int count = 0;
        cv::Mat image(height, width, CV_8UC3);
        uchar* pxvec =image.ptr<uchar>(0);
        
        for(int row = 0; row < height; row++)
        {
            pxvec = image.ptr<uchar>(row);
            for(int col = 0; col < width; col++)
            {
                for(int c = 0; c < 3; c++)
                {
                    pxvec[col*3+c] = frame_data[count];
                    count++;
                }
            }
        }
    
        cv::Mat gray_img, smd_image_x, smd_image_y, G;
        if (image.channels() == 3){
            cv::cvtColor(image, gray_img, CV_BGR2GRAY);
        }
    
        cv::Mat kernel_x(3, 3, CV_32F, cv::Scalar(0));
        kernel_x.at<float>(1, 2) = -1.0;
        kernel_x.at<float>(1, 1) = 1.0;
        cv::Mat kernel_y(3, 3, CV_32F, cv::Scalar(0));
        kernel_y.at<float>(1, 1) = 1.0;
        kernel_y.at<float>(2, 1) = -1.0;
        cv::filter2D(gray_img, smd_image_x, gray_img.depth(), kernel_x);
        cv::filter2D(gray_img, smd_image_y, gray_img.depth(), kernel_y);
    
        smd_image_x = cv::abs(smd_image_x);
        smd_image_y = cv::abs(smd_image_y);
        cv::multiply(smd_image_x, smd_image_y, G);

        // std::cout << "smd2: " << cv::mean(G)[0] << std::endl;
        return cv::mean(G)[0];
    }
}


/**         
* 能量梯度函数 
*   
* Inputs:   
* @param image:  
* Return: double    
*/
extern "C"
{
    double energy_gradient(int height, int width, uchar* frame_data)
    {
        int count = 0;
        cv::Mat image(height, width, CV_8UC3);
        uchar* pxvec =image.ptr<uchar>(0);
        
        for(int row = 0; row < height; row++)
        {
            pxvec = image.ptr<uchar>(row);
            for(int col = 0; col < width; col++)
            {
                for(int c = 0; c < 3; c++)
                {
                    pxvec[col*3+c] = frame_data[count];
                    count++;
                }
            }
        }
    
        cv::Mat gray_img, smd_image_x, smd_image_y, G;
        if (image.channels() == 3){
            cv::cvtColor(image, gray_img, CV_BGR2GRAY);
        }
    
        cv::Mat kernel_x(3, 3, CV_32F, cv::Scalar(0));
        kernel_x.at<float>(1, 2) = -1.0;
        kernel_x.at<float>(1, 1) = 1.0;
        cv::Mat kernel_y(3, 3, CV_32F, cv::Scalar(0));
        kernel_y.at<float>(1, 1) = 1.0;
        kernel_y.at<float>(2, 1) = -1.0;
        cv::filter2D(gray_img, smd_image_x, gray_img.depth(), kernel_x);
        cv::filter2D(gray_img, smd_image_y, gray_img.depth(), kernel_y);
    
        cv::multiply(smd_image_x, smd_image_x, smd_image_x);
        cv::multiply(smd_image_y, smd_image_y, smd_image_y);
        G = smd_image_x + smd_image_y;

        // std::cout << "energy_gradient: " << cv::mean(G)[0] << std::endl;
        return cv::mean(G)[0];
    }
}

/**         
* EAV点锐度算法函数 
*   
* Inputs:   
* @param image:  
* Return: double    
*/
extern "C"
{
    double eav(cv::Mat &image)
    {
        // assert(image.empty());
    
        cv::Mat gray_img, smd_image_x, smd_image_y, G;
        if (image.channels() == 3){
            cv::cvtColor(image, gray_img, CV_BGR2GRAY);
        }
    
        double result = .0f;
        for (int i = 1; i < gray_img.rows-1; ++i){
            uchar *prev = gray_img.ptr<uchar>(i - 1);
            uchar *cur = gray_img.ptr<uchar>(i);
            uchar *next = gray_img.ptr<uchar>(i + 1);
            for (int j = 0; j < gray_img.cols; ++j){
                result += (abs(prev[j - 1] - cur[i])*0.7 + abs(prev[j] - cur[j]) + abs(prev[j + 1] - cur[j])*0.7 +
                    abs(next[j - 1] - cur[j])*0.7 + abs(next[j] - cur[j]) + abs(next[j + 1] - cur[j])*0.7 +
                    abs(cur[j - 1] - cur[j]) + abs(cur[j + 1] - cur[j]));
            }
        }
        
        return result / gray_img.total();
    }
}

/**         
* 误差灵敏度分析和结构相似度分析 
*   
* Inputs:   
* @param i1:  
* @param i2:  
* Return: double    
*/
extern "C"
{
    double ssim(cv::Mat &i1, cv::Mat & i2)
    {
        const double C1 = 6.5025, C2 = 58.5225;
        int d = CV_32F;
        cv::Mat I1, I2;
        i1.convertTo(I1, d);
        i2.convertTo(I2, d);
        cv::Mat I1_2 = I1.mul(I1);
        cv::Mat I2_2 = I2.mul(I2);
        cv::Mat I1_I2 = I1.mul(I2);
        cv::Mat mu1, mu2;
        GaussianBlur(I1, mu1, cv::Size(11, 11), 1.5);
        GaussianBlur(I2, mu2, cv::Size(11, 11), 1.5);
        cv::Mat mu1_2 = mu1.mul(mu1);
        cv::Mat mu2_2 = mu2.mul(mu2);
        cv::Mat mu1_mu2 = mu1.mul(mu2);
        cv::Mat sigma1_2, sigam2_2, sigam12;
        GaussianBlur(I1_2, sigma1_2, cv::Size(11, 11), 1.5);
        sigma1_2 -= mu1_2;
        GaussianBlur(I2_2, sigam2_2, cv::Size(11, 11), 1.5);
        sigam2_2 -= mu2_2;
        GaussianBlur(I1_I2, sigam12, cv::Size(11, 11), 1.5);
        sigam12 -= mu1_mu2;
        cv::Mat t1, t2, t3;
        t1 = 2 * mu1_mu2 + C1;
        t2 = 2 * sigam12 + C2;
        t3 = t1.mul(t2);
    
        t1 = mu1_2 + mu2_2 + C1;
        t2 = sigma1_2 + sigam2_2 + C2;
        t1 = t1.mul(t2);
    
        cv::Mat ssim_map;
        divide(t3, t1, ssim_map);
        cv::Scalar mssim = cv::mean(ssim_map);
    
        double ssim = (mssim.val[0] + mssim.val[1] + mssim.val[2]) / 3;
        return ssim;
    }
}
 
/**         
* NRSS梯度结构相似度 
*   
* Inputs:   
* @param image:  
* Return: double    
*/
extern "C"
{
    double nrss(int height, int width, uchar* frame_data)
    {
        int count = 0;
        cv::Mat image(height, width, CV_8UC3);
        uchar* pxvec =image.ptr<uchar>(0);
        
        for(int row = 0; row < height; row++)
        {
            pxvec = image.ptr<uchar>(row);
            for(int col = 0; col < width; col++)
            {
                for(int c = 0; c < 3; c++)
                {
                    pxvec[col*3+c] = frame_data[count];
                    count++;
                }
            }
        }

        cv::Mat gray_img, Ir, G, Gr;
        if (image.channels() == 3){
            cv::cvtColor(image, gray_img, CV_BGR2GRAY);
        }
    
        //构造参考图像
        cv::GaussianBlur(gray_img, Ir, cv::Size(7, 7), 6, 6);
    
        //提取图像和参考图像的梯度信息
        cv::Sobel(gray_img, G, CV_32FC1, 1, 1);//计算原始图像sobel梯度
        cv::Sobel(Ir, Gr, CV_32FC1, 1, 1);//计算构造函数的sobel梯度
    
        //找出梯度图像 G 中梯度信息最丰富的 N 个图像块,n=64(即划分为8x8的大小)
        //计算每个小方块的宽/高
        int block_cols = G.cols * 2 / 9;
        int block_rows = G.rows * 2 / 9;
        //获取方差最大的block
        cv::Mat best_G,best_Gr;
        float max_stddev = .0f;
        int pos = 0;
        for (int i = 0; i < 64; ++i){
            int left_x = (i % 8)*(block_cols / 2);
            int left_y = (i / 8)*(block_rows / 2);
            int right_x = left_x + block_cols;
            int right_y = left_y + block_rows;
    
            if (left_x < 0) left_x = 0;
            if (left_y < 0) left_y = 0;
            if (right_x >= G.cols) right_x = G.cols - 1;
            if (right_y >= G.rows) right_y = G.rows - 1;
    
            cv::Rect roi(left_x,left_y,right_x-left_x,right_y-left_y);
            cv::Mat temp=G(roi).clone();
            cv::Scalar mean,stddev;
            cv::meanStdDev(temp, mean, stddev);
            if (stddev.val[0]>max_stddev){
                max_stddev = static_cast<float>(stddev.val[0]);
                pos = i;
                best_G = temp;
                best_Gr = Gr(roi).clone();
            }
        }
        
        //计算结构清晰度NRSS
        double result = 1 - ssim(best_G, best_Gr);
    
        return result;
    }
}


compile.sh

[ ! -f $1 ] && exit

srcfile=$1

srcname=${1##*/};
# g++ -g $srcfile -o ${srcname%.*} `pkg-config --cflags --libs opencv`
# g++ hello.cpp -fPIC -shared -o libhello.so

g++ $srcfile -o ${srcname%.*}.so -std=c++11 -lopencv_core -lopencv_highgui -lopencv_imgproc -shared -fPIC

# g++ src/blur_detection.cpp -o lib/blur_detection.so -std=c++11 -lopencv_core -lopencv_highgui -lopencv_imgproc -shared -fPIC

参考:
https://github.com/Leezhen2014/python–/blob/master/BlurDetection.py

https://www.pyimagesearch.com/2015/09/07/blur-detection-with-opencv/

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值