吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3116|回复: 3
收起左侧

[会员申请] 申请会员ID:autumoon【申请通过】

[复制链接]
吾爱游客  发表于 2020-6-22 10:58
1、申 请 I D:autumoon
2、个人邮箱:autumoon#vip.qq.com
3、原创技术文章:本人测绘行业,做图像处理的,主攻c++ 图像增强,识别 算法等,业余也写一些图像处理小工具,下面展示一下之前做过的自动识别影像中的房屋,道路,绿植,水域的软件。 如下图,需要在正射影像中使用图像自动识别算法,识别出道路,房屋,绿植,水域等。

简单说下方法,实际上肯定比较复杂,道路的特点是比较长,直线,通常亮度比较高等;而房屋通常是矩形,蓝色和红色的屋顶用颜色就比较好识别;至于绿植,主要靠颜色,一般直接使用rgb模型,g分量大到一定程度即可。


先看下效果,也有部分识别错误:



核心检测代码:
[C++] 纯文本查看 复制代码
double IsDefAreaEx(unsigned char* pBuffer, const int& nDetectIndex, CAreaLinesEx* pInput, CAreaLinesEx* pSample /*= nullptr*/, double lfGSD /*= 1.0*/)
{
        //输出用
        double dResult = 0.0;
        
        int nPartialRGBIndex = pInput->GetPartialRGB();

        //获得基础参数
        double dArea = pInput->GetArea();
        double dRectArea = pInput->BoundingRectArea();
        double dVariance = pInput->GetVarianceRef();

        if (dArea < 1e-5 || dRectArea < 1e-5)
        {
                return 0.0;
        }

        //计算区域的部分参数
        CAreaLinesEx ale(*pInput);        //必须备份,不然会改变原来的值
        CAreaRect arc = ale.GetBoundingRect();
        int left = arc.left;
        int down = arc.down;
        int buffer_width = arc.Width();
        int buffer_height = arc.Height();
        if (buffer_width > 10000 || buffer_height > 10000)
        {
                return dResult;
        }
        std::vector<std::vector<cv::Point>> vContours;
        //当前区域索引
        int nFindIndex = -1;
        //直方图统计的宽度
        double dHistWidth = 1.0;
        //区域边界,检测直线的数目
        int nFindLines = 0;
        std::vector<cv::Vec4i> lines;

        //绿植无需检测
        if (nDetectIndex != 1)
        {
                //偏移区域
                ale.Offset(-arc.left, -arc.down, true);
                memset(pBuffer, 0, buffer_width * buffer_height * sizeof(unsigned char));
                ale.WriteBoundBuffer(pBuffer, buffer_width, buffer_height);
                cv::Mat mSrcGray = COpencvUser::TransBufferToMat(pBuffer, buffer_width, buffer_height, 1, 1, false);

                //外扩两个像素,方便检测边缘直线
                cv::Mat mSrcGrayExpand = cv::Mat::zeros(cv::Size(mSrcGray.cols + 4, mSrcGray.rows + 4), mSrcGray.type());
                mSrcGray.copyTo(mSrcGrayExpand(cv::Rect(2,2, mSrcGray.cols, mSrcGray.rows)));
                mSrcGray = mSrcGrayExpand;

                size_t nAreaCount = COpencvUser::GetContours(mSrcGray.clone(), vContours);
                if (nAreaCount)
                {
                        double dMaxArea = 0.0;
                        for (size_t i = 0; i < nAreaCount; ++i)
                        {
                                if (vContours[i].size() < 4)
                                {
                                        continue;
                                }

                                double dContourArea = cv::contourArea(vContours[i]);

                                if (nFindIndex != -1)
                                {
                                        if (dContourArea > dMaxArea)
                                        {
                                                dMaxArea = dContourArea;
                                                nFindIndex = i;
                                        }
                                }
                                else
                                {
                                        dMaxArea = dContourArea;
                                        nFindIndex = i;
                                }
                        }
                }


                //在区域中搜寻直线
                //cv::Mat mShow;
                //const int nRProp = 3;
                //cv::resize(mSrcGray, mShow, cv::Size(mSrcGray.cols * nRProp, mSrcGray.rows * nRProp));
                //cv::imshow("D:\\hough.tif", mShow);
                cv::Canny(mSrcGray, mSrcGray, 100.0, 200.0);
                //cv::resize(mSrcGray, mShow, cv::Size(mSrcGray.cols * nRProp, mSrcGray.rows * nRProp));
                //cv::imshow("D:\\canny.tif", mShow);
                nFindLines = (int)COpencvUser::HoughLinesProb(mSrcGray.clone(), lines, 15, 2 / lfGSD, 0);

                //cv::Mat mSrcBGR;
                //cv::cvtColor(mSrcGray, mSrcBGR, CV_GRAY2BGR);
                //COpencvUser::HoughLinesShow(mSrcBGR, lines);
                //cv::resize(mSrcBGR, mShow, cv::Size(mSrcGray.cols * nRProp, mSrcGray.rows * nRProp));
                //cv::imshow("D:\\lines.tif", mShow);
                //cv::waitKey();

                //求得截断长度
                if (nFindIndex != -1 && vContours[nFindIndex].size() > 4)
                {
                        cv::RotatedRect roRc = cv::fitEllipse(vContours[nFindIndex]);
                        double dAngle = roRc.angle;
                        //cv::imwrite("D:\\area.tif", mSrcGray);
                        cv::Point2f VerPts[4];
                        roRc.points(VerPts);
                        double dGap1 = sqrt((VerPts[0].x - VerPts[1].x)*(VerPts[0].x - VerPts[1].x) + (VerPts[0].y - VerPts[1].y)*(VerPts[0].y - VerPts[1].y));
                        double dGap2 = sqrt((VerPts[1].x - VerPts[2].x)*(VerPts[1].x - VerPts[2].x) + (VerPts[1].y - VerPts[2].y)*(VerPts[1].y - VerPts[2].y));

#ifdef OUTPUT_LINE_IMG
                        cv::Mat mLineBGR;
                        cv::cvtColor(mSrcGray, mLineBGR, CV_GRAY2BGR);
                        cv::RNG rng;
                        for (size_t i = 0; i < 4; ++i)
                        {
                                cv::Point p1 = VerPts[i];
                                cv::Point p2 = VerPts[(i + 1) % 4];
                                cv::line(mLineBGR, p1, p2, cv::Scalar(rng.uniform(0.0, 255.0),rng.uniform(0.0, 255.0),rng.uniform(0.0, 255.0)));
                        }
                        cv::imwrite("D:\\areaR.tif", mLineBGR);
                        static int nTimes = 0;
                        nTimes++;
#endif // OUTPUT_LINE_IMG

                        cv::Rect bdRc = roRc.boundingRect();
                        if (dGap1 > 10.0)
                        {
                                //用得到的角度,切多边形,得到的线段宽度,求直方图统计值,中间的80%的数据的平均值
                                CSegment sg(VerPts[0].x, VerPts[0].y, VerPts[1].x, VerPts[1].y);
                                std::vector<POINT32F> vRasterPts = sg.Raster(2.0); //以像素为单位
                                std::vector<CSegment> vGapLines;
                                for (size_t i = 0; i < vRasterPts.size(); ++i)
                                {
                                        double a = 0.0, b = 0.0, c = 0.0;
                                        CSegment::CalcLineABC(dAngle, vRasterPts[i].x, vRasterPts[i].y, a, b, c);

                                        POINT32F pt1, pt2;
                                        CSegment::IsLineInterRect(a, b, c, MyRect(bdRc.x, bdRc.y, bdRc.width, bdRc.height), pt1, pt2);

                                        CSegment sgCut(pt1, pt2);
                                        std::vector<POINT32F> vRasterCutPts = sgCut.Raster();
                                        bool bFindStart = false;
                                        POINT32F ptStart, ptEnd;
                                        size_t nRasterCutPtCount = vRasterCutPts.size();
                                        for (size_t j = 0; j < nRasterCutPtCount; ++j)
                                        {
                                                if (cv::pointPolygonTest(vContours[nFindIndex], cv::Point2f(vRasterCutPts[j].x, vRasterCutPts[j].y), false) >= 0)
                                                {
                                                        if (!bFindStart)
                                                        {
                                                                bFindStart = true;
                                                                ptStart = vRasterCutPts[j];
                                                        }

                                                        if (bFindStart && j == nRasterCutPtCount - 1)
                                                        {
                                                                ptEnd = vRasterCutPts[j];
                                                                vGapLines.push_back(CSegment(ptStart, ptEnd));
                                                        }
                                                }
                                                else
                                                {
                                                        if (bFindStart)
                                                        {
                                                                ptEnd = vRasterCutPts[j];
                                                                vGapLines.push_back(CSegment(ptStart, ptEnd));
                                                                bFindStart = false;
                                                        }
                                                }
                                        }
                                        
                                }

                                std::multimap<double, int> mdiGap;
                                for (size_t j = 0; j < vGapLines.size(); ++j)
                                {
                                        double leng = vGapLines[j].Length();
                                        mdiGap.insert(std::make_pair(leng, j));
#ifdef OUTPUT_LINE_IMG
                                        cv::line(mLineBGR, cv::Point(vGapLines[j].x1, vGapLines[j].y1), cv::Point(vGapLines[j].x2, vGapLines[j].y2),
                                                cv::Scalar(rng.uniform(0.0, 255.0),rng.uniform(0.0, 255.0),rng.uniform(0.0, 255.0)));
#endif // OUTPUT_LINE_IMG
                                }

                                //转换map为vector
                                std::vector<double> vLength;
                                size_t nLineCount = mdiGap.size();
                                vLength.reserve(nLineCount);
                                for (auto it = mdiGap.begin(); it != mdiGap.end(); ++it)
                                {
                                        vLength.push_back(it->first);
                                }

                                size_t idxStart = nLineCount * 0.1;
                                size_t idxEnd = nLineCount * 0.9;

                                double dHistLength = 0.0;
                                for (size_t j = idxStart; j < idxEnd; ++j)
                                {
                                        dHistLength += vLength[j];
                                }
                                dHistLength /= idxEnd - idxStart + 1;

                                dHistWidth = dHistLength * lfGSD;

                                //此时,更新旋转矩形信息
                                pInput->m_ri.bUseful = true;
                                pInput->m_ri.dHistLength = dHistLength;
                                pInput->m_ri.dRotateRectLength = dGap1;
                                pInput->m_ri.dRotateRectWidth = dGap2;
                                pInput->m_ri.nHistLengthCount = idxEnd - idxStart + 1;
                        }
                        else
                        {
                                dHistWidth = MIN(dGap1, dGap2) * lfGSD;

                                //此时,更新旋转矩形信息
                                pInput->m_ri.bUseful = true;
                                pInput->m_ri.dHistLength = MIN(dGap1, dGap2);
                                pInput->m_ri.dRotateRectLength = dGap1;
                                pInput->m_ri.dRotateRectWidth = dGap2;
                                pInput->m_ri.nHistLengthCount = MAX(dGap1, dGap2);
                        }

#ifdef OUTPUT_LINE_IMG
                        cv::imwrite("D:\\areaL.tif", mLineBGR);
#endif // OUTPUT_LINE_IMG
                }
        }

        switch (nDetectIndex)
        {
        case DETECT_HOUSE:
                {
                        //房屋,必须存在至少一组平行或者垂直的线段
                        size_t nPPLines = ParallelOrPerpendLines(lines);
                        if (nPPLines > 0)
                        {
                                //如果检测多组直角,并且他们能够对应起来(平行或者垂直),则更容易是房屋,提高可能性
                                //房屋的实际面积
                                double dRealArea = dArea * lfGSD * lfGSD;
                                double dAreaProbablity = 1.0;
                                double dHouseWidthProb = 1.0;
                                double dLengthWidthProb = 1.0;
                                double dVarianceProb = 1.0;
                                //房屋面积在10-200的范围外,则降低其可能性
                                if (dRealArea < 10.0)
                                {
                                        dAreaProbablity = dRealArea / 10.0;
                                }
                                else if (dRealArea > 200.0)
                                {
                                        dRealArea = 1000.0 / dRealArea;
                                }

                                double dGrayValueProb = 1.0;
                                //如果亮度小于30,则越小越不可能是房子
                                std::vector<uchar> vRGB = CAreaLinesEx::VectorHSV2RGB(ale.GetAvgHSVRef());
                                uchar uValue = (vRGB[0] + vRGB[1] + vRGB[2]) / 3;

                                if (uValue < 30)
                                {
                                        dGrayValueProb = uValue / 30.0;
                                }

                                if (nFindIndex != -1 && vContours[nFindIndex].size() > 4)
                                {
                                        cv::RotatedRect roRc = cv::fitEllipse(vContours[nFindIndex]);
                                        cv::Point2f VerPts[4];
                                        roRc.points(VerPts);

                                        double dGap1 = sqrt((VerPts[0].x - VerPts[1].x)*(VerPts[0].x - VerPts[1].x) + (VerPts[0].y - VerPts[1].y)*(VerPts[0].y - VerPts[1].y));
                                        double dGap2 = sqrt((VerPts[1].x - VerPts[2].x)*(VerPts[1].x - VerPts[2].x) + (VerPts[1].y - VerPts[2].y)*(VerPts[1].y - VerPts[2].y));
                                        double droRcArea = dGap1 * dGap2;

                                        //旋转矩形占比
                                        double dAreaRectProb = dArea / droRcArea;

                                        if (dAreaRectProb < 0.2)
                                        {
                                                return dResult;
                                        }

                                        //房屋宽度不应该介于一定的范围
                                        if (dHistWidth < 1.0)
                                        {
                                                dHouseWidthProb = dHistWidth / 1.0;
                                        }
                                        else if (dHistWidth > 10.0)
                                        {
                                                dHouseWidthProb = 10.0 / dHistWidth;
                                        }

                                        //如果区域的长度和宽度的比值过大,则降低可能性
                                        double dLengWidthProp = dGap1 * lfGSD / dHistWidth;
                                        if (dLengWidthProp > 5.0)
                                        {
                                                dLengthWidthProb = 5.0 / dLengWidthProp;
                                        }
                                        //CLOG::Out(_T("dLengthWidthProb = %lf"), dLengthWidthProb);
                                        dResult = dAreaRectProb * dAreaProbablity * dHouseWidthProb /** dLengthWidthProb*/;
                                        //直接增加概率
                                        if (dResult < 0.5 && nPPLines > 1)
                                        {
                                                dResult += 0.5;
                                        }

                                        return dResult;
                                }

                                //正矩形占比
                                return (dArea / dRectArea) * dAreaProbablity * dHouseWidthProb * dGrayValueProb;
                        }
                }
                break;
        case DETECT_GREEN:
                {
                        //绿植
                        if (nPartialRGBIndex == 1 && dVariance > 60.0)
                        {
                                //可以增加平行直线的检测

                                return 1.0;
                        }
                }
                break;
        case DETECT_WATER:
                {
                        //水域
                        if (nPartialRGBIndex != -1)
                        {
                                return dResult;
                        }

                        //水域方差通常较小,而面积比较大,截断距离也较大
                        double dVarianceProb = 1.0;
                        if (dVariance > 20.0)
                        {
                                dVarianceProb = 20 / dVariance;
                        }

                        //面积,小于40则降低可能性
                        //水域的实际面积
                        double dRealArea = dArea * lfGSD * lfGSD;
                        double dAreaProbablity = 1.0;
                        //水域面积,优先考虑40.0以上的区域
                        if (dRealArea < 40.0)
                        {
                                dAreaProbablity = dRealArea / 40.0;
                        }

                        //水域的截断长度,通常较大
                        double dHistWidthProb = 1.0;

                        //截断宽度如果小于30m,则降低可能性
                        if (dHistWidth < 30.0)
                        {
                                dHistWidthProb = dHistWidth / 30.0;
                        }

                        return dVarianceProb * dAreaProbablity * dHistWidthProb;

                }
                break;
        case DETECT_ROAD:
                {
                        if (nPartialRGBIndex != -1 || nFindLines < 2)
                        {
                                return dResult;
                        }

                        //至少存在一条接近平行的线段组
                        std::vector<cv::Vec4i> vParaLines = ParallelLines(lines);
                        size_t nParaLineCount = vParaLines.size();
                        if (nParaLineCount == 0)
                        {
                                return dResult;
                        }

                        //判断检测到的直线中,至少存在两条直线接近平行
                        double dSumLength = 0.0;
                        for (size_t i = 0; i < nParaLineCount; ++i)
                        {
                                dSumLength += V4iLength(vParaLines[i]);
                        }

                        double dRealLength = dSumLength * lfGSD / nParaLineCount;

                        //道路检测到的平行直线组长度和
                        double dLengthProb = 1.0;

                        if (dRealLength < 10)
                        {
                                dLengthProb = dRealLength / 10;
                        }

                        //道路宽度比重
                        double dWidthProbability = 1.0;
                        //区域面积和外界旋转矩形的面积比
                        double dAreaPropProbablity = 1.0;
                        //旋转矩形的宽高比例
                        double drcLengthProb = 1.0;
                        double dLengWidthPropProbility = 1.0;
                        if (nFindIndex != -1 && vContours[nFindIndex].size() > 4)
                        {
                                cv::RotatedRect roRc = cv::fitEllipse(vContours[nFindIndex]);
                                cv::Point2f VerPts[4];
                                roRc.points(VerPts);

                                double dGap1 = sqrt((VerPts[0].x - VerPts[1].x)*(VerPts[0].x - VerPts[1].x) + (VerPts[0].y - VerPts[1].y)*(VerPts[0].y - VerPts[1].y));
                                double dGap2 = sqrt((VerPts[1].x - VerPts[2].x)*(VerPts[1].x - VerPts[2].x) + (VerPts[1].y - VerPts[2].y)*(VerPts[1].y - VerPts[2].y));

                                double droRcArea = dGap1 * dGap2;
                                dAreaPropProbablity = 1 - dArea / droRcArea;

                                //需要重新求得道路的统计宽度
                                double dLength = MAX(dGap1, dGap2) * lfGSD;
                                double dLengWidthProp = MAX(dGap1, dGap2) / dHistWidth;

                                if (dLength < 50.0)
                                {
                                        drcLengthProb = dLength  / 50.0;
                                }

                                //如果小于1m则减小可能性
                                if (dHistWidth < 1.0)
                                {
                                        dWidthProbability = dHistWidth;
                                }
                                else if (dHistWidth > 20.0)
                                {
                                        dWidthProbability =  20.0 / dHistWidth;
                                }

                                //长宽比例越长,越可能是道路
                                if (dLengWidthProp < 3.0)
                                {
                                        dLengWidthPropProbility = dLengWidthProp / 3.0;
                                }
                        }

#ifdef PROBABLITY_LOG
                        //输出各概率到log
                        CLOG::Out(_T("dLengthProb = %f dWidthProbability = %f dAreaPropProbablity = %f drcLengthProb = %f dLengWidthPropProbility = %f IsRoadArea = %f"),
                                dLengthProb, dWidthProbability, dAreaPropProbablity, drcLengthProb, dLengWidthPropProbility, pInput->IsRoadArea(pSample, lfGSD));
#endif // PROBABLITY_LOG

                        return dLengthProb * dWidthProbability * dAreaPropProbablity * drcLengthProb * dLengWidthPropProbility * pInput->IsRoadArea(pSample, lfGSD);
                }
                break;
        default:
                break;
        }

        return dResult;
}


另外,也展示一个业余写的图像处理小工具,本工具可以显示16位彩色影像(一般的图像处理工具只支持8位),还有快速分类图片等文件,改变尺寸,克隆EXIF,转换图片格式等,采用了多线程处理,支持gif动画的缩放和去色。

最新版软件下载地址:http://pan.baidu.com/s/1eSPG4RS


PictureTools功能简介,快速分类图片等文件,改变尺寸,克隆EXIF,转换图片格式等,采用了多线程处理,支持gif动画的缩放和去色。

详细帖子与教程:https://tieba.baidu.com/p/5915492672


clone exif:

还有其他小工具,都免费下载,简单说明一下
CreateTif                创建任意颜色任意大小的tif文件。
GrabFilesFromFilters            通过vs工程中的.filters文件获取对应的文件
GrabHeadFiles                通过cpp等文件,获取必要的头文件等
RenameByTxt                通过txt重命名文件夹下的文件,如果是音乐文件会连带修改标题
VideoClassify                按照视频的分辨率对视频进行分类
VsProjectCleaner            清理vs工程目录

本次更新日志:
1.新增了 视频按照尺寸(也就是分辨率)分类 小工具

历史日志
//针对PictureTools
1.缩放单张gif动画的时候,增加了进度显示功能
2.优化了调整分辨率时自动输出的参数

1.增加了固定宽高的功能
2.增加了去掉颜色的功能

1增加了对输出JPG图像质量的设置
2.去掉了gdal相关的组件,采用纯 CxImage组件

1.增加了转换格式的功能,并提供保持文件EXIF信息和修改时间的功能
2.优化了代码,提高了处理文件的速度

1.增加了多文件和多文件夹拖拽到软件界面的功能
2.增加了多文件和多文件夹拖拽到exe文件或者软件快捷方式的功能

希望申请能够通过,谢谢版主!


发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2020-6-23 10:46
I D:autumoon
邮箱:autumoon#vip.qq.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。
吾爱游客  发表于 2020-6-23 12:40
已经登录啦,需要两个小时之后才能回复,谢谢版主通过申请,稍后我用帐号登录回帖。
autumoon 发表于 2020-6-23 13:09
Hmily 发表于 2020-6-23 10:46
I D:autumoon
邮箱:autumoon#vip.qq.com

来报道啦,谢谢版主通过申请!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 01:25

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表