opencv入门,尝试基于积分图像进行盒式滤波

问题遇到的现象和发生背景
遇到的现象和发生背景,请写出第一个错误信息

输出的图像是一张几乎完全黑的图片(只有边缘没有做处理的地方显示出来)

img

#include                 
#include     
#include 
#include    
using namespace std;
using namespace cv;

void myboxfilter(int filter_size, Mat& image_input, Mat& image_output)
{
    image_output = image_input.clone();
    int k = (filter_size - 1) / 2;


    Mat image_integral;
    integral(image_input, image_integral, CV_32F);
    Mat imageIntegralNorm;
    normalize(image_integral, image_integral, 0, 255, NORM_MINMAX);
    convertScaleAbs(image_integral, imageIntegralNorm);


    //进行盒式滤波
    for (int i = k; i < (image_input.rows - k); i++)
    {

        for (int j = k; j < (image_input.cols - k); j++)
        {
            int sum_r = 0, sum_g = 0, sum_b = 0;
            Vec3b& pixel1 = imageIntegralNorm.at(i - k, j - k);
            Vec3b& pixel2 = imageIntegralNorm.at(i - k, j + k);
            Vec3b& pixel3 = imageIntegralNorm.at(i + k, j - k);
            Vec3b& pixel4 = imageIntegralNorm.at(i + k, j + k);

            sum_r = pixel4[2] + pixel1[2] - pixel2[2] - pixel3[2];
            sum_g = pixel4[1] + pixel1[1] - pixel2[1] - pixel3[1];
            sum_b = pixel4[0] + pixel1[0] - pixel2[0] - pixel3[0];

            Vec3b& pixel5 = image_output.at(i, j);
            pixel5[2] = round(sum_r / (filter_size * filter_size));
            pixel5[1] = round(sum_g / (filter_size * filter_size));
            pixel5[0] = round(sum_b / (filter_size * filter_size));
        }

    }
}


int main()
{
  
    Mat srcImage = imread("test.jpg");
    if (!srcImage.data)
    {
        cout << "读取失败!\n";
        system("pause");
        return -1;
    }
    imshow("original image", srcImage);

    Mat dstImage;
    myboxfilter(3,srcImage, dstImage);
    imshow("after myboxfilter", dstImage);
    imwrite("box_filtering.jpg", dstImage);


    waitKey(0);
    return 0;
}

我想要达到的结果

输出经过盒式滤波的彩色图片

myboxfilter 函数中进行积分图像的计算和归一化时,使用了 normalize 和 convertScaleAbs 两个函数。但是它们的使用似乎不太正确,因为在计算积分图像后,像素值已经是浮点型 CV_32F 类型的数值,不需要进行归一化和类型转换。这部分代码可以简化为:
scss
Copy code
Mat image_integral;
integral(image_input, image_integral, CV_32F);
在 myboxfilter 函数中,对于输入图像的边缘区域并没有进行处理。因此,在进行像素遍历时需要注意边界的处理,避免访问越界导致程序崩溃。

在 myboxfilter 函数中,进行像素计算时使用了 round 函数对浮点型像素值进行四舍五入。但是,由于 round 函数返回的是整型数值,因此可能会导致计算结果不太准确。可以考虑使用 cv::saturate_cast 函数将浮点型数值转换为合理的像素类型。

在 main 函数中,没有使用 waitKey 函数等待用户按下按键后才退出程序。这可能会导致窗口一闪而过,用户无法看到处理结果。可以在最后添加如下代码:

scss
Copy code
waitKey(0);
这样可以等待用户按下任意键后才退出程序,用户可以看到处理结果

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/681284
  • 我还给你找了一篇非常好的博客,你可以看看是否有帮助,链接:opencv 测试代码运行时遇到的一些错误记录 | 笔记
  • 除此之外, 这篇博客: 利用opencv实现检测特定颜色物体,并追踪其移动中的  如果大家有什么更好的方法提出,麻烦在下方评论区留个言,,抱抱大腿。 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    效果图如下:

    import numpy as np
    import cv2
    import argparse
    from collections import deque
    
    cap = cv2.VideoCapture(0)
    
    pts = deque(maxlen=128)
    
    lower_red = np.array([0, 80, 50])
    upper_red = np.array([8, 255, 220])
    
    lower_green = np.array([50, 120, 50])
    upper_green = np.array([77, 255, 255])
    
    while True:
        ret, img = cap.read()
        img = img[:, :-50]
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)  # 将捕获的视频帧由RBG转HSV
    
        kernel = np.ones((3, 3), np.uint8)
        # 将处于lower_green 和upper_green 区间外的值全部置为0,区间内的值置为255
        mask = cv2.inRange(hsv, lower_green, upper_green)
    
        # mask_pencil = cv2.inRange()
        # 对mask图像进行腐蚀,将一些小的白色区域消除,将图像“变瘦”, iterations代表使用erode的次数
        # erode就是让图像中白色部分变小
        mask = cv2.erode(mask, kernel, iterations=2)
        # 开运算 (MORPH_OPEN):先腐蚀再膨胀
        # 删除不能包含结构元素的对象区域,平滑图像的轮廓,使拐点的地方更加连贯,断开一些狭窄的链接,去掉细小的突出部分。
        # 在这里使用开运算就是为了使除笔头外的噪声区域尽量的消除
        mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)
    
        # dilate膨胀就是将白色区域变大,黑色的区域减小
        mask = cv2.dilate(mask, kernel, iterations=5)
        # bitwise_and对二进制数据进行“与”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“与”操作
        # 与操作后,白色区域的部分就会保存下来,黑色区域(为0)与后就还是为0
        res = cv2.bitwise_and(img, img, mask=mask)
    
        '''
        findContours() 查找检测物体的轮廓。
        第一个参数是寻找轮廓的图像;
        第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
            cv2.RETR_EXTERNAL表示只检测外轮廓
            cv2.RETR_LIST检测的轮廓不建立等级关系
            cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。
            如果内孔内还有一个连通物体,这个物体的边界也在顶层。
            cv2.RETR_TREE建立一个等级树结构的轮廓。
    
        第三个参数method为轮廓的近似办法
            cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,
            即max(abs(x1-x2),abs(y2-y1))==1
            cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,
            例如一个矩形轮廓只需4个点来保存轮廓信息
    
            cv2.findContours()函数返回两个值:contours:hierarchy,一个是轮廓本身,还有一个是每条轮廓对应的属性。
            findContours函数首先返回一个list(即contours),list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示
    
        '''
        cnts, heir = cv2.findContours(mask.copy(), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)[-2:]
        center = None
    
        if len(cnts) > 0:  # 如果检测出了轮廓
            c = max(cnts, key=cv2.contourArea)  # 以轮廓的面积为条件,找出最大的面积
            ((x, y), radius) = cv2.minEnclosingCircle(c)  # 找出最小的圆
    
            M = cv2.moments(c)
            center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
            if radius > 5:
                cv2.circle(img, (int(x), int(y)), int(radius), (0, 255, 255), 2)
                cv2.circle(img, center, 5, (0, 0, 255), -1)
    
        pts.appendleft(center)
        for i in range(1, len(pts)):
            if pts[i - 1] is None or pts[i] is None:
                    # if pts[i - 1] == pts[i]:
                continue
            thick = int(np.sqrt(len(pts) / float(i + 1)) * 2.5)
            cv2.line(img, pts[i - 1], pts[i], (0, 0, 225), thick)  # 画线
    
        cv2.imshow("img", img)
        cv2.imshow("mask", mask)
        cv2.imshow("res", res)
    
    
        k = cv2.waitKey(30) & 0xFF
        if k == 32:
            break
    # cleanup the camera and close any open windows
    cap.release()
    cv2.destroyAllWindows()
    

     


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^