FT(IG)显著+分割+Surf识别笔记
- FT代码注释
- Mean Shift分割代码“
- Surf部分`
代码块
//FT显著
#include "Saliency.h"
#include "cmath"
//这只是显著部分,要自己写个main函数,读取图像,还要转成灰度图,太累了不复制了
> void Saliency::RGB2LAB(
const vector<unsigned int>& ubuff,
vector<double>& lvec,
vector<double>& avec,
vector<double>& bvec)
{//这部分是求RGB转到LAB的过程,要经过转XYZ的过程
int sz = int(ubuff.size());
lvec.resize(sz);
avec.resize(sz);
bvec.resize(sz);
for( int j = 0; j < sz; j++ )
{
int r = (ubuff[j] >> 16) & 0xFF;
int g = (ubuff[j] >> 8) & 0xFF;
int b = (ubuff[j] ) & 0xFF;
double xval = 0.412453 * r + 0.357580 * g + 0.180423 * b;
double yval = 0.212671 * r + 0.715160 * g + 0.072169 * b;
double zVal = 0.019334 * r + 0.119193 * g + 0.950227 * b;
xval /= (255.0 * 0.950456);
yval /= 255.0;
zVal /= (255.0 * 1.088754);
double fX, fY, fZ;
double lval, aval, bval;
if (yval > 0.008856)
{
fY = pow(yval, 1.0 / 3.0);
lval = 116.0 * fY - 16.0;
}
else
{
fY = 7.787 * yval + 16.0 / 116.0;
lval = 903.3 * yval;
}
if (xval > 0.008856)
fX = pow(xval, 1.0 / 3.0);
else
fX = 7.787 * xval + 16.0 / 116.0;
if (zVal > 0.008856)
fZ = pow(zVal, 1.0 / 3.0);
else
fZ = 7.787 * zVal + 16.0 / 116.0;
aval = 500.0 * (fX - fY)+128.0;
bval = 200.0 * (fY - fZ)+128.0;
lvec[j] = lval;
avec[j] = aval;
bvec[j] = bval;
}
}
/// 高斯平滑
void Saliency::GaussianSmooth(
const vector<double>& inputImg,
const int& width,
const int& height,
const vector<double>& kernel,
vector<double>& smoothImg)
{
int center = int(kernel.size())/2;
int sz = width*height;
smoothImg.clear();
smoothImg.resize(sz);
vector<double> tempim(sz);
int rows = height;
int cols = width;
// Blur in the x direction.
{int index(0);
for( int r = 0; r < rows; r++ )
{
for( int c = 0; c < cols; c++ )
{
double kernelsum(0);
double sum(0);
for( int cc = (-center); cc <= center; cc++ )
{
if(((c+cc) >= 0) && ((c+cc) < cols))
{
sum += inputImg[r*cols+(c+cc)] * kernel[center+cc];
kernelsum += kernel[center+cc];
}
}
tempim[index] = sum/kernelsum;
index++;
}
}}
// Blur in the y direction.
{int index = 0;
for( int r = 0; r < rows; r++ )
{
for( int c = 0; c < cols; c++ )
{
double kernelsum(0);
double sum(0);
for( int rr = (-center); rr <= center; rr++ )
{
if(((r+rr) >= 0) && ((r+rr) < rows))
{
sum += tempim[(r+rr)*cols+c] * kernel[center+rr];
kernelsum += kernel[center+rr];
}
}
smoothImg[index] = sum/kernelsum;
index++;
}
}}
}
/// GetSaliencyMap
///
/// Outputs a saliency map with a value assigned per pixel. The values are
/// normalized in the interval [0,255] if normflag is set true (default value).
void Saliency::GetSaliencyMap(
const vector<unsigned int>& inputimg,
const int& width,
const int& height,
vector<double>& salmap,
const bool& normflag)
{
int sz = width*height;
salmap.clear();
salmap.resize(sz);
vector<double> lvec(0), avec(0), bvec(0);
RGB2LAB(inputimg, lvec, avec, bvec);
// Obtain Lab average values
double avgl(0), avga(0), avgb(0);
{for( int i = 0; i < sz; i++ )
{
avgl += lvec[i];
avga += avec[i];
avgb += bvec[i];
}}
avgl /= sz;
avga /= sz;
avgb /= sz;
vector<double> slvec(0), savec(0), sbvec(0);
// The kernel can be [1 2 1] or [1 4 6 4 1] as needed.
// The code below show usage of [1 2 1] kernel.
vector<double> kernel(0);
//高斯滤波的核是[1,2,1]
kernel.push_back(1.0);
kernel.push_back(2.0);
kernel.push_back(1.0);
GaussianSmooth(lvec, width, height, kernel, slvec); //高斯平滑
GaussianSmooth(avec, width, height, kernel, savec);
GaussianSmooth(bvec, width, height, kernel, sbvec);
{for( int i = 0; i < sz; i++ ) //得到的结果高斯平滑减去原始图像的均值,如果有低频信号通过图像平滑最后减去均值就没有响应了,相反高频部分,通过平滑残留了高频响应减去了均值还是有响应,这部分我们认为是显著区域,最后返回结果
{
salmap[i] = (slvec[i]-avgl)*(slvec[i]-avgl) +
(savec[i]-avga)*(savec[i]-avga) +
(sbvec[i]-avgb)*(sbvec[i]-avgb);
}}
//以上就是FT求图像显著图的主要代码
if( true == normflag )//这是归一化,就是每个图像像素值都缩小为[0-1]的函数。函数为Normalize
{
vector<double> normalized(0);
Normalize(salmap, width, height, normalized);
swap(salmap, normalized);
}
}
//分割代码
#include "stdafx.h"
//stdafx.h要自己建一个这样的库
// meanshift_segmentation.cpp : 定义控制台应用程序的入口点。
//
#include"opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "iostream"
#pragma comment(lib,"opencv_highgui2413d.lib")
#pragma comment(lib,"opencv_core2413d.lib")
#pragma comment(lib,"opencv_imgproc2413d.lib")
using namespace cv;
using namespace std;
Mat src, dst;
int spatialRad, colorRad, maxPryLevel;
int main(int argc, uchar* argv[])
{
int maxPyrLevel = 3; //金字塔层数
Mat res;
double duration = static_cast<double>(getTickCount());
Mat img = imread("E:/Codes/CprimerPlus/chapter13/分割/31.jpg"); //读图路径
//路径要加引号,一般程序出错最有可能是路径问题,有绝对路径和相对路径之分,绝对路径:/
//相对路径:可直接引用程序下的图片
int spatialRad = 4; //值越大时间会越长
int colorRad = 30; //值越大图像会分割的区域数越小
pyrMeanShiftFiltering(img, res, spatialRad, colorRad, maxPyrLevel);
imshow("res", res);
RNG rng = theRNG();
Mat mask(res.rows + 2, res.cols + 2, CV_8UC1, Scalar::all(0)); //掩模
for (int y = 0; y < res.rows; y++)
{
for (int x = 0; x < res.cols; x++)
{
if (mask.at<uchar>(y + 1, x + 1) == 0) //非0处即为1,表示已经经过填充,不再处理
{
//Scalar newVal(rng(256), rng(256), rng(256));
//floodFill(res, mask, Point(x, y), newVal, 0, Scalar::all(5), Scalar::all(5)); //执行漫水填充
}
}
}
imshow("meanShift图像分割", res);
imwrite("result.jpg", res);
duration = ((double)getTickCount() - duration) / getTickFrequency();
cout << "运行时间" << duration << "秒" << endl;
waitKey();
return 0;
}
Surf部分没什么好写的,基本是OPENCV3书上原装程序,要说所有程序完全是我自己写的只有得到分割后将它扣出来,其他都是主程序,自己修修小数据
#include "stdafx.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
#include "iostream"
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat binary;
Mat result = imread("2.jpg", 0);//这里0表示读取图像并转为灰度图即[0-255]
Mat tongji;
threshold(result, binary, 50, 255, CV_THRESH_BINARY);//阀值化,固定阀值吧,不是自适应的。
//里面的参数分别代表;输入图像;输出图像;最低阀值,往上为1,下为0;这个图像里像素值的最大///值;二值化的表示,也有其他表示方法
Mat element = getStructuringElement(MORPH_RECT, Size(50, 50));//膨胀操作的一个自定义核
Mat out;
double maxArea = 0;
vector<cv::Point> maxContour;
dilate(binary, out, element);//膨胀。一般写前面三个参数,后面有默认的
vector<vector<cv::Point>> contours;//vector是结构体或者容器
findContours(out, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//寻找轮廓
//里面参数:输入;输出;检测轮廓类别,这个是检测最外围轮廓(还有所有轮廓并放list中,提取所有轮廓//并组织为双层结构,最后一个是提取轮廓建立网状结构);获取轮廓的每个像素。
for (int i = 0; i < contours.size(); i++)
{
double area = contourArea(contours[i]);//轮廓面积
if (area > maxArea)
{
maxArea = area;
maxContour = contours[i];
}
}
Rect maxRect = boundingRect(maxContour);//求最大轮廓面积,并返回轮廓的最大矩形
Mat original = imread("1.jpg");//原图
Mat gray = result;
Mat hole(gray.size(), CV_8U, Scalar(0));//建立模版方便抠图所用的转换,与原图大小一样
rectangle(hole, Rect(maxRect.x, maxRect.y, maxRect.width, maxRect.height), Scalar(255, 255, 255), -1, 1, 0);//刚刚矩形的位置,在模版相同的矩形位置变白色
double a = maxRect.x;
double b = maxRect.y;
double c = maxRect.width;
double d = maxRect.height;
printf("左上点x:%f\n", a);
printf("左上点y:%f\n", b);
printf("宽:%f\n", c);
printf("高:%f\n", d);//显示矩形的位置数据
namedWindow("My hole");
imshow("My hole", hole);
Mat crop(original.rows, original.cols, CV_8UC3);
original.copyTo(crop, hole);//将原图像拷贝进遮罩图层
namedWindow("My warpPerspective");
imshow("My warpPerspective", crop);
imwrite("result.jpg", crop);
imshow("image", result);
waitKey();
return 0;
}