OpenCv图像处理基础例子(C++版)

一、创建图像

void QuickDemo::mat_creation_demo(Mat &image) {
	//克隆,复制
    Mat m1, m2;
    m1 = image.clone();
    image.copyTo(m2);
    // 创建空白图像
    Mat m3 = Mat::zeros(Size(88, 88), CV_8UC3);//大小8*8像素,8位3通道
    m3 = Scalar(0, 0, 255);//上色,三通道分别为B,G,R,取值范围均在0~255
    std::cout << "width: " << m3.cols << " height: " << m3.rows << " channels: "<<m3.channels()<< std::endl;
    // std::cout << m3 << std::endl;

    Mat m4;
    m3.copyTo(m4);
    m4 = Scalar(0, 255, 255);
    imshow("图像", m3);
    imshow("图像4", m4);
}

二、像素读写

void QuickDemo::pixel_visit_demo(Mat &image) {
    int w = image.cols;//获取图像宽度
    int h = image.rows;//获取图像高度
    int dims = image.channels();//获取图像通道数

    /*
    //图像颜色反转
    for (int row = 0; row < h; row++) {
        for (int col = 0; col < w; col++) {
            if (dims == 1) { // 灰度图像
                int pv = image.at<uchar>(row, col);
                image.at<uchar>(row, col) = 255 - pv;
            }
            if (dims == 3) { // 彩色图像
                Vec3b bgr = image.at<Vec3b>(row, col);
                image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
                image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
                image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
            }
        }
    }
    */

    for (int row = 0; row < h; row++) {
    	uchar* current_row = image.ptr<uchar>(row);
    	for (int col = 0; col < w; col++) {
            if (dims == 1) { // 灰度图像
                int pv = *current_row;
                *current_row++ = 255 - pv;
            }
            if (dims == 3) { // 彩色图像
                *current_row++ = 255 - *current_row;
                *current_row++ = 255 - *current_row;
                *current_row++ = 255 - *current_row;
            }
        }
    }
    imshow("像素读写演示", image);
}

三、算术操作

加:add()        add(image, m, dst);

减:subtract()        subtract(image, m, dst);

乘:multiply()        multiply(image, m, dst);

除:divide()        divide(image, m, dst);

限制值的范围:saturate_cast        saturate_cast<uchar>(a + b);//将a+b限制在uchar之内,结果大于255,则为255;小于0,则为0

void QuickDemo::operators_demo(Mat &image) {
    Mat dst = Mat::zeros(image.size(), image.type());
    Mat m = Mat::zeros(image.size(), image.type());
    m = Scalar(5, 5, 5);

    // 加法
    /*
    int w = image.cols;
    int h = image.rows;
    int dims = image.channels();
    for (int row = 0; row < h; row++) {
        for (int col = 0; col < w; col++) {
            Vec3b p1 = image.at<Vec3b>(row, col);
            Vec3b p2 = m.at<Vec3b>(row, col);
            dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
            dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
            dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
        }
    }
    */
    divide(image, m, dst);

    imshow("加法操作", dst);
}

四、滚动条

static void on_lightness(int b, void* userdata) {//亮度回调函数
    Mat image = *((Mat*)userdata);
    Mat dst = Mat::zeros(image.size(), image.type());
    Mat m = Mat::zeros(image.size(), image.type());
    addWeighted(image, 1.0, m, 0, b, dst);
    imshow("亮度与对比度调整", dst);
}

static void on_contrast(int b, void* userdata) {//对比度回调函数
	Mat image = *((Mat*)userdata);
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	double contrast = b / 100.0;
	addWeighted(image, contrast, m, 0.0, 0, dst);
	imshow("亮度与对比度调整", dst);
}

void QuickDemo::tracking_bar_demo(Mat &image) {
	namedWindow("亮度与对比度调整", WINDOW_AUTOSIZE);
	int lightness = 50;
	int max_value = 100;
	int contrast_value = 100;
	createTrackbar("Value Bar:", "亮度与对比度调整", &lightness, max_value, on_lightness, (void*) (&image));
	createTrackbar("Contrast Bar:", "亮度与对比度调整", &contrast_value, 200, on_contrast, (void*)(&image));
	on_lightness(50, &image);
}

五、键盘响应

void QuickDemo::key_demo(Mat &image) {
    Mat dst = Mat::zeros(image.size(), image.type());
    while (true) {
        int c = waitKey(100);
        if (c == 27) { // 退出
            break;
        }
        if (c == 49) { // Key #1
            std::cout << "you enter key # 1 "<< std::endl;
            cvtColor(image, dst, COLOR_BGR2GRAY);
        }
        if (c == 50) { // Key #2
            std::cout << "you enter key # 2 " << std::endl;
            cvtColor(image, dst, COLOR_BGR2HSV);
        }
        if (c == 51) { // Key #3
            std::cout << "you enter key # 3 " << std::endl;
            dst = Scalar(50, 50, 50);
            add(image, dst, dst);
        }
        imshow("键盘响应", dst);
    }
}

六、颜色表操作

void QuickDemo::color_style_demo(Mat &image) {
    int colormap[] = {
        COLORMAP_AUTUMN,
        COLORMAP_BONE,
        COLORMAP_JET,
        COLORMAP_WINTER,
        COLORMAP_RAINBOW,
        COLORMAP_OCEAN,
        COLORMAP_SUMMER,
        COLORMAP_SPRING,
        COLORMAP_COOL,
        COLORMAP_PINK,
        COLORMAP_HOT,
        COLORMAP_PARULA,
        COLORMAP_MAGMA,
        COLORMAP_INFERNO,
        COLORMAP_PLASMA,
        COLORMAP_VIRIDIS,
        COLORMAP_CIVIDIS,
        COLORMAP_TWILIGHT,
        COLORMAP_TWILIGHT_SHIFTED
    };

    Mat dst;
    int index = 0;
    while (true) {
        int c = waitKey(500);
        if (c == 27) { // 退出
            break;
        }
        applyColorMap(image, dst, colormap[index%19]);
        index++;
        imshow("颜色风格", dst);
    }
}

七、像素逻辑操作

与:bitwise_and(m1,m2,dst);

或:bitwise_or(m1,m2,dst);

非:bitwise_not(image,dst); 图像取反操作,dst = ~image;

异或:bitwise_xor(m1,m2,dst)

void QuickDemo::bitwise_demo(Mat &image) {
    Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
    Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
    rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);//画出一个矩形(名,位置及大小,颜色,线宽(>0绘制,<0填充),?,?)
    rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
    imshow("m1", m1);
    imshow("m2", m2);
    Mat dst;
    bitwise_xor(m1, m2, dst);//逻辑操作函数
    imshow("像素位操作", dst);
}

八、通道合并与分离

void QuickDemo::channels_demo(Mat &image) {
    std::vector<Mat> mv;
    split(image, mv);//分离图像
    imshow("蓝色", mv[0]);
    imshow("绿色", mv[1]);
    imshow("红色", mv[2]);//分离出三个单通道,显示为灰度图像

    Mat dst;
    mv[0] = 0;
    mv[1] = 0;
    merge(mv, dst);//合并图像
    imshow("红色", dst);

    int from_to[] = { 0, 2, 1,1, 2, 0 }; //0,2交换,1,1交换,2,0交换
    mixChannels(&image, 1, &dst, 1, from_to, 3);//通道交换函数(图片地址,图片数量,生成图片地址,图片数量,交换方式,交换通道数量)
    imshow("通道混合", dst);
}

九、色彩空间转换

void QuickDemo::inrange_demo(Mat &image) {
    Mat hsv;
    cvtColor(image, hsv, COLOR_BGR2HSV);//色彩空间转换
    Mat mask;
    inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);//提取图片中绿色,具体hsv色彩见最上面

    Mat redback = Mat::zeros(image.size(), image.type());
    redback = Scalar(40, 40, 200);
    bitwise_not(mask, mask);//非运算,留下出绿色外的
    imshow("mask", mask);
    image.copyTo(redback, mask);//将绿色外的图片复制到红色背景上
    imshow("roi区域提取", redback);
}

十、像素值统计

void QuickDemo::pixel_statistic_demo(Mat &image) {
    double minv, maxv;
    Point minLoc, maxLoc;
    std::vector<Mat> mv;
    split(image, mv);
    for (int i = 0; i < mv.size(); i++) {
        minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());
        std::cout <<"No. channels:"<< i << " min value:" << minv << " max value:" << maxv << std::endl;
    }
    Mat mean, stddev;
    Mat redback = Mat::zeros(image.size(), image.type());
    redback = Scalar(40, 40, 200);
    meanStdDev(redback, mean, stddev);
    imshow("redback", redback);
    std::cout << "means:" << mean << std::endl;
    std::cout<< " stddev:" << stddev << std::endl;
}

十一、几何图形绘制

void QuickDemo::drawing_demo(Mat &image) {
    Rect rect;
    rect.x = 100;//确定x位置
    rect.y = 100;//确定y位置
    rect.width = 250;//宽
    rect.height = 300;//高
    Mat bg = Mat::zeros(image.size(), image.type());//创建Mat
    rectangle(bg, rect, Scalar(0, 0, 255), -1, 8, 0);//绘制方形
    circle(bg, Point(350, 400), 15, Scalar(255, 0, 0), -1, 8, 0);//绘制圆形(图像,圆心,半径,颜色,线宽,?,?)
    line(bg, Point(100, 100), Point(350, 400), Scalar(0, 255, 0), 4, LINE_AA, 0);//绘制线(图像,点,点,颜色,宽度,?,?)
    RotatedRect rrt;
    rrt.center = Point(200, 200);//中心点
    rrt.size = Size(100, 200);//大小
    rrt.angle = 90.0;//旋转角度
    ellipse(bg, rrt, Scalar(0, 255, 255), 2, 8);//绘制椭圆(图像,位置大小,颜色,线宽,?)
    Mat dst;
    addWeighted(image, 0.7, bg, 0.3, 0, dst);
    imshow("绘制演示", bg);
}

十二、随机数与随机颜色

void QuickDemo::random_drawing() {
    Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
    int w = canvas.cols;
    int h = canvas.rows;
    RNG rng(12345);//产生随机数函数
    while (true) {
        int c = waitKey(10);
        if (c == 27) { // 退出
            break;
        }
        int x1 = rng.uniform(0, w);//产生(0,w)的随机数
        int y1 = rng.uniform(0, h);//产生(0,h)的随机数
        int x2 = rng.uniform(0, w);//产生(0,w)的随机数
        int y2 = rng.uniform(0, h);//产生(0,h)的随机数
        int b = rng.uniform(0, 255);//产生(0,255)的随机数
        int g = rng.uniform(0, 255);//产生(0,255)的随机数
        int r = rng.uniform(0, 255);//产生(0,255)的随机数
        // canvas = Scalar(0, 0, 0);
        line(canvas, Point(x1, y1), Point(x2, y2), Scalar(b, g, r), 1, LINE_AA, 0);
        imshow("随机绘制演示", canvas);
    }
}

十三、多边形绘制与填充

void QuickDemo::polyline_drawing_demo() {
    Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);//新建画布
    int w = canvas.cols;//获取宽
    int h = canvas.rows;//获取高
    Point p1(100, 100);
    Point p2(300, 150);
    Point p3(300, 350);
    Point p4(250, 450);
    Point p5(50, 450);
    std::vector<Point> pts;
    pts.push_back(p1);
    pts.push_back(p2);
    pts.push_back(p3);
    pts.push_back(p3);
    pts.push_back(p4);
    pts.push_back(p5);
    //fillPoly(canvas, pts, Scalar(255, 0, 255), 8, 0);//填充图形
    // polylines(canvas, pts, true, Scalar(0, 255, 0), -1, 8, 0);//绘制边框
    std::vector<std::vector<Point>> contours;//构造多个点集的集合
    contours.push_back(pts);
    drawContours(canvas, contours, 0, Scalar(0, 0, 255), -1, 8);//绘制/填充多边形(图像,点集,绘制第几个(全部:-1),颜色,线宽,?)
    imshow("绘制多边形", canvas);
}

十四、鼠标操作与响应

Point sp(-1, -1);
Point ep(-1, -1);
Mat temp;
static void on_draw(int event, int x, int y, int flags, void *userdata) {
	Mat image = *((Mat*)userdata);
	if (event == EVENT_LBUTTONDOWN) {
		sp.x = x;
		sp.y = y;
		std::cout <<"start point:" << sp << std::endl;
	}
	else if (event == EVENT_LBUTTONUP) {
		ep.x = x;
		ep.y = y;
		int dx = ep.x - sp.x;
		int dy = ep.y - sp.y;
		if (dx > 0 && dy > 0) {
				Rect box(sp.x, sp.y, dx, dy);
				temp.copyTo(image);
				imshow("ROI区域", image(box));
				rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
				imshow("鼠标绘制", image);
				// ready for next drawing
				sp.x = -1;
				sp.y = -1;
		}
	}
	else if (event == EVENT_MOUSEMOVE) {
		if (sp.x > 0 && sp.y > 0) {
			ep.x = x;
			ep.y = y;
			int dx = ep.x - sp.x;
			int dy = ep.y - sp.y;
			if (dx > 0 && dy > 0) {
				Rect box(sp.x, sp.y, dx, dy);
				temp.copyTo(image);
				rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
				imshow("鼠标绘制", image);
			}
		}
	}
}

void QuickDemo::mouse_drawing_demo(Mat &image) {
	namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
	setMouseCallback("鼠标绘制", on_draw, (void*)(&image));
	imshow("鼠标绘制", image);
	temp = image.clone();
}

十五、图像像素类型转换与归一化

四种归一化:

NORM_MINMAX;(最常用)

NORM_INF;

NORM_L1;

NORM_L2;

void QuickDemo::norm_demo(Mat &image) {
    Mat dst;
    std::cout << image.type() << std::endl;
    image.convertTo(image, CV_32F);//数据类型转换,转换为浮点数类型
    std::cout << image.type() << std::endl;
    normalize(image, dst, 1.0, 0, NORM_MINMAX);//归一化函数
    std::cout << dst.type() << std::endl;
    imshow("图像数据归一化", dst);
    // CV_8UC3, CV_32FC3
}

十六、图像放缩与插值

void QuickDemo::resize_demo(Mat &image) {
    Mat zoomin, zoomout;
    int h = image.rows;
    int w = image.cols;
    resize(image, zoomin, Size(w / 2, h / 2), 0, 0, INTER_LINEAR);//图像缩放(输入图像,输出图像,缩放大小,拉伸x轴(0-1),拉伸y轴(0-1),插值方法(线性插值))	**放缩大小和拉伸二选其一**
    imshow("zoomout", zoomout);//缩小
    resize(image, zoomout, Size(w*1.5, h*1.5), 0, 0, INTER_LINEAR);
    imshow("zoomin", zoomin);//放大
}

十七、图像翻转

void QuickDemo::flip_demo(Mat &image) {
    Mat dst;
    // flip(image, dst, 0); // 上下翻转,x轴对称
    // flip(image, dst, 1); // 左右翻转,y轴对称
    flip(image, dst, -1); // 180°旋转,中心对称
    imshow("图像翻转", dst);
}

十八、图像旋转

void QuickDemo::rotate_demo(Mat &image) {
    Mat dst, M;
    int w = image.cols;
    int h = image.rows;
    M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1.0);//获取图像数组(原来图像中心位置,旋转角度,缩放倍数)
    //计算新的宽高
    double cos = abs(M.at<double>(0, 0));
    double sin = abs(M.at<double>(0, 1));
    int nw = cos*w + sin*h;//新宽
    int nh = sin*w + cos*h;//新高
    M.at<double>(0, 2) += (nw / 2 - w / 2);//新中心位置
    M.at<double>(1,2) += (nh / 2 - h / 2);//新中心位置
    warpAffine(image, dst, M, Size(nw, nh), INTER_LINEAR, 0, Scalar(255, 255, 0));//旋转图片(输入,输出,图像数组,输出大小,插值方法,?,颜色)
    imshow("旋转演示", dst);
}

十九、视频文件处理与保存

void QuickDemo::video_demo(Mat &image) {
    VideoCapture capture("D:/images/video/example_dsh.mp4");//初始化对象
    int frame_width = capture.get(CAP_PROP_FRAME_WIDTH);//获取每帧宽度
    int frame_height = capture.get(CAP_PROP_FRAME_HEIGHT);//获取每帧高度
    int count = capture.get(CAP_PROP_FRAME_COUNT);//获取总帧数
    double fps = capture.get(CAP_PROP_FPS);//获取帧率
    std::cout << "frame width:" << frame_width << std::endl;
    std::cout << "frame height:" << frame_height << std::endl;
    std::cout << "FPS:" << fps << std::endl;
    std::cout << "Number of Frames:" << count << std::endl;
    VideoWriter writer("D:/test.mp4", capture.get(CAP_PROP_FOURCC), fps, Size(frame_width, frame_height), true);//保持视频(视频名,视频编码格式(直接获取如该代码),帧率,视频宽高,?)
    Mat frame;
    while (true) {
        capture.read(frame);
        flip(frame, frame, 1);
        if (frame.empty()) {
            break;
        }
        imshow("frame", frame);
        colorSpace_Demo(frame);
        writer.write(frame);//保持视频
        // TODO: do something....
        int c = waitKey(1);
        if (c == 27) { // 退出
            break;
        }
    }

    // release
    capture.release();
    writer.release();
}

二十、图像直方图

void QuickDemo::histogram_demo(Mat &image) {
    // 三通道分离
    std::vector<Mat> bgr_plane;
    split(image, bgr_plane);
    // 定义参数变量
    const int channels[1] = { 0 };
    const int bins[1] = { 256 };
    float hranges[2] = { 0,255 };
    const float* ranges[1] = { hranges };
    Mat b_hist;
    Mat g_hist;
    Mat r_hist;
    // 计算Blue, Green, Red通道的直方图
    calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);//计算直方图(图像,图像张数,通道,蒙版,输出,维度(1维),?,范围?)
    calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
    calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);

    // 显示直方图
    int hist_w = 512;
    int hist_h = 400;
    int bin_w = cvRound((double)hist_w / bins[0]);
    Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
    // 归一化直方图数据
    normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    // 绘制直方图曲线
    for (int i = 1; i < bins[0]; i++) {
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
    }
    // 显示直方图
    namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
    imshow("Histogram Demo", histImage);
}

二十一、二维直方图

void QuickDemo::histogram_2d_demo(Mat &image) {
    // 2D 直方图
    Mat hsv, hs_hist;
    cvtColor(image, hsv, COLOR_BGR2HSV);
    int hbins = 30, sbins = 32;
    int hist_bins[] = { hbins, sbins };
    float h_range[] = { 0, 180 };
    float s_range[] = { 0, 256 };
    const float* hs_ranges[] = { h_range, s_range };
    int hs_channels[] = { 0, 1 };
    calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, false);
    double maxVal = 0;
    minMaxLoc(hs_hist, 0, &maxVal, 0, 0);
    int scale = 10;
    Mat hist2d_image = Mat::zeros(sbins*scale, hbins * scale, CV_8UC3);
    for (int h = 0; h < hbins; h++) {
        for (int s = 0; s < sbins; s++)
        {
            float binVal = hs_hist.at<float>(h, s);
            int intensity = cvRound(binVal * 255 / maxVal);
            rectangle(hist2d_image, Point(h*scale, s*scale),
                Point((h + 1)*scale - 1, (s + 1)*scale - 1),
                Scalar::all(intensity),
                -1);
        }
    }
    applyColorMap(hist2d_image, hist2d_image, COLORMAP_JET);
    imshow("H-S Histogram", hist2d_image);
    imwrite("D:/hist_2d.png", hist2d_image);
}

二十二、直方图均衡化

void QuickDemo::histogram_eq_demo(Mat &image) {
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    imshow("灰度图像", gray);
    Mat dst;
    equalizeHist(gray, dst);
    imshow("直方图均衡化演示", dst);
}

二十三、图像卷积操作

void QuickDemo::blur_demo(Mat &image) {
Mat dst;
blur(image, dst, Size(15, 15), Point(-1, -1));
imshow("图像模糊", dst);
}

二十四、高斯模糊

void QuickDemo::gaussian_blur_demo(Mat &image) {
    Mat dst;
    GaussianBlur(image, dst, Size(0, 0), 15);//(输入,输出,卷积核大小,σ参数)	**size和σ只需要一个,一般设置σ**
    imshow("高斯模糊", dst);
}

二十五、高斯双边模糊

void QuickDemo::bifilter_demo(Mat &image) {
    Mat dst;
    bilateralFilter(image, dst, 0, 100, 10);//(输入,输出)
    imshow("双边模糊", dst);
}

二十六、人脸识别实例

*注意更改自己文件位置

void QuickDemo::face_detection_demo() {
    std::string root_dir = "D:/opencv-4.4.0/opencv/sources/samples/dnn/face_detector/";
    dnn::Net net = dnn::readNetFromTensorflow(root_dir+ "opencv_face_detector_uint8.pb", root_dir+"opencv_face_detector.pbtxt");
    VideoCapture capture("D:/images/video/example_dsh.mp4");
    Mat frame;
    while (true) {
        capture.read(frame);
        if (frame.empty()) {
            break;
        }
        Mat blob = dnn::blobFromImage(frame, 1.0, Size(300, 300), Scalar(104, 177, 123), false, false);
        net.setInput(blob);// NCHW
        Mat probs = net.forward(); // 
        Mat detectionMat(probs.size[2], probs.size[3], CV_32F, probs.ptr<float>());
        // 解析结果
        for (int i = 0; i < detectionMat.rows; i++) {
            float confidence = detectionMat.at<float>(i, 2);
            if (confidence > 0.5) {
                int x1 = static_cast<int>(detectionMat.at<float>(i, 3)*frame.cols);
                int y1 = static_cast<int>(detectionMat.at<float>(i, 4)*frame.rows);
                int x2 = static_cast<int>(detectionMat.at<float>(i, 5)*frame.cols);
                int y2 = static_cast<int>(detectionMat.at<float>(i, 6)*frame.rows);
                Rect box(x1, y1, x2 - x1, y2 - y1);
                rectangle(frame, box, Scalar(0, 0, 255), 2, 8, 0);
            }
        }
        imshow("人脸检测演示", frame);
        int c = waitKey(1);
        if (c == 27) { // 退出
            break;
        }
    }
}

注:所有代码均来自OpenCV4 C++ 快速入门视频30讲 - 系列合集

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中进行数字图像处理,你可以使用一些专门为图像处理设计的库或者自己实现一些基本的图像处理算法。以下是一个简单的示例代码,演示如何在C语言中实现图像灰度化处理: ```c #include <stdio.h> #include <stdlib.h> #include <stdint.h> typedef struct { uint8_t r, g, b; } RGBPixel; void rgb2gray(RGBPixel* rgbImage, uint8_t* grayImage, int width, int height) { for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { // 使用加权平均法将RGB图像转换为灰度图像 uint8_t grayValue = (uint8_t)(0.299 * rgbImage[i * width + j].r + 0.587 * rgbImage[i * width + j].g + 0.114 * rgbImage[i * width + j].b); grayImage[i * width + j] = grayValue; } } } int main() { // 假设图像大小为100x100 int width = 100; int height = 100; // 分配RGB图像和灰度图像的内存空间 RGBPixel* rgbImage = (RGBPixel*)malloc(width * height * sizeof(RGBPixel)); uint8_t* grayImage = (uint8_t*)malloc(width * height * sizeof(uint8_t)); // 读入RGB图像数据(此处省略,假设已经读入图像数据到rgbImage中) // 将RGB图像转换为灰度图像 rgb2gray(rgbImage, grayImage, width, height); // 处理后的灰度图像可以进行进一步的操作,例如保存至文件或显示出来 // 释放内存 free(rgbImage); free(grayImage); return 0; } ``` 在这个示例中,我们定义了一个`RGBPixel`结构体,用于表示RGB图像的一个像素点。然后,我们实现了一个`rgb2gray()`函数,将RGB图像转换为灰度图像。最后,在`main()`函数中,我们分配了RGB图像和灰度图像的内存空间,并调用`rgb2gray()`函数进行图像处理。 请注意,这只是一个简单的示例,实际的数字图像处理涉及到更多复杂的算法和技术。你可以根据需求选择适当的库或自行实现算法来进行更高级的图像处理操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值