手撸kmeans(c++)实现,用于图像的主色调提取(1)

想到那天头条面试时,让我手撸kmeans,奈何好久不用c++,好多都忘了==淡淡的忧伤

这次刚好赶上机会,可以再试试了,我写成项目了,有多个文件

首先:base.h

#ifndef BASE_H
#define BASE_H
#include<iostream>
#include<opencv2/opencv.hpp>
#include<cassert>
#include<stdlib.h>
class Baseofgeo{
public:
  float computedis(const std::vector<float> p1,const std::vector<float> p2);
  void Gekmeasns(std::vector<std::vector<float> >& listA,int K);
private:
//to do...
};
#endif

 再上:base.cpp

#include"base.h"

void Baseofgeo::Gekmeasns(std::vector<std::vector<float> >& listA,int K){

  //初始化
   srand((unsigned)time(NULL));
   std::vector<std::vector<float> > centerid(K,std::vector<float> (3,0.0));
   int len=listA.size();
   for (int i=0;i<K;){
     int randomindex=rand()%len;
     if(listA[randomindex][3]!=-1.0){continue;}

     listA[randomindex][3]=i;
     centerid[i][0]=listA[randomindex][0];
     centerid[i][1]=listA[randomindex][1];
     centerid[i][2]=listA[randomindex][2];
     i++;
  }

  //计算距离
  int count=0;//迭代次数
  float J1=0.0;//记录上一次迭代后的类内距离
  float reserror=100.0;//记录连续两次类内距离的变化
  while( count<=20 && reserror>10.0){
   std::cout<<"第"<<count<<"次迭代"<<std::endl;
    //对每个点遍历,计算与其最接近的中心,并赋上类别
  for(std::vector<float>& p1:listA){
    std::vector<float> pp1(3,0.0);
    pp1[0]=p1[0];pp1[1]=p1[1];pp1[2]=p1[2];
    float mindist=99999999.0;
    for(int j=0;j<centerid.size();j++){
      std::vector<float> p2=centerid[j];
      float distt=computedis(pp1,p2);
      if(distt<mindist){
	mindist=distt;
	p1[3]=(float)j;
      }
    }

  }
  //重新计算中心
  for(int i=0;i<K;i++){
    std::vector<float> sum(3,0.0); float numb=0.0;
    for(std::vector<float> p:listA){
      if((int)p[3]==i){
	sum[0]+=p[0];sum[1]+=p[1];sum[2]+=p[2];
	numb++;
      }
    }
    assert(numb!=0);
    sum[0]/=numb;sum[1]/=numb;sum[2]/=numb;
    centerid[i]=sum;

  }

  //计算终止条件1
  count++;
  //计算终止条件2
  float J=0.0;
  for(int i=0;i<K;i++){
    for(std::vector<float> p:listA ){
      if ((int)p[3]==i){
	std::vector<float> ptem(3,0.0);
	ptem[0]=p[0];ptem[1]=p[1];ptem[2]=p[2];
	J+=computedis(ptem,centerid[i]);
      }
    }
  }
  //
  if (count==1){
    //记录上次的类内距离之和
    J1=J;
  }else{
    reserror=std::abs(J-J1);
    std::cout<<"reserror:"<<reserror<<std::endl;
    //记录上次的类内距离之和
    J1=J;
  }
  }
}

float Baseofgeo::computedis(const std::vector<float> p1,const std::vector<float> p2){
  assert(p1.size()==3&&p2.size()==3);
  return std::sqrt(pow(p1[0]-p2[0],2)+pow(p1[1]-p2[1],2)+pow(p1[2]-p2[2],2));

}

主函数嘛:main.cpp

#include<iostream>
#include<vector>
#include<boost/concept_check.hpp>
#include<opencv2/opencv.hpp>
#include<time.h>
#include<stdlib.h>
#include<cassert>
#include<memory>
#include"base.h"

int main(int argc,char** argv){

  cv::Mat  I=cv::imread("../data/0001.jpg");
  cv::imshow("im a pic",I);
  std::vector<std::vector<float> >   listA(I.cols*I.rows,std::vector<float>(4,-1.0));
 int nl=d_Ihsv.rows;
 int nc=d_Ihsv.cols;
 int ii=0;
 for(int i=0;i<nl;i++){
   for(int j=0;j<nc;j++){
    listA[ii][0]=I.at<cv::Vec3f>(i,j)[0]/10.0;
    listA[ii][1]=I.at<cv::Vec3f>(i,j)[1]/10.0;
    listA[ii][2]=I.at<cv::Vec3f>(i,j)[2]/10.0;
    ii++;

  }

}
 std::shared_ptr<Baseofgeo> basemethod(new Baseofgeo());
 basemethod->Gekmeasns(listA,72);//就当我是可视化==,可视化第二期再更
 for(auto p:listA){
 std::cout<<p[3]<<std::endl;
}
  return 0;
}

还有CMakeLists.txt

cmake_minimum_required( VERSION 2.8 )
project ( image )

set(OpenCV_DIR "/home/geo/opencv-2.4.13/build")
add_compile_options(-std=c++11)

find_package(OpenCV REQUIRED)
add_library(base base.cpp)
target_link_libraries(  base
  ${OpenCV_LIBS})

add_executable(main main.cpp)
target_link_libraries(main
    base
    ${OpenCV_LIBS})
时间: 2024-07-30 23:13:19

手撸kmeans(c++)实现,用于图像的主色调提取(1)的相关文章

.NET手撸2048小游戏

.NET手撸2048小游戏 2048是一款益智小游戏,得益于其规则简单,又和2的倍数有关,因此广为人知,特别是广受程序员的喜爱. 本文将再次使用我自制的"准游戏引擎"FlysEngine,从空白窗口开始,演示如何"手撸"2048小游戏,并在编码过程中感受C#的魅力和.NET编程的快乐. 说明:FlysEngine是封装于Direct2D,重复本文示例,只需在.NET Core 3.0下安装NuGet包FlysEngine.Desktop即可. 并不一定非要做一层封装

.NET手撸绘制TypeScript类图——上篇

.NET手撸绘制TypeScript类图--上篇 近年来随着交互界面的精细化,TypeScript越来越流行,前端的设计也越来复杂,而类图正是用简单的箭头和方块,反映对象与对象之间关系/依赖的好方式.许多工具都能生成C#类图,有些工具也能生成TypeScript类图,如tsuml,但存在一些局限性. 我们都是.NET开发,为啥不干脆就用.NET撸一个TypeScript类图呢? 说干就干!为了搞到类图,一共分两步走: 解析.ts文件,生成抽象语法树(AST),并转换为简单的类.属性.方法等对象

99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!|建议收藏!!!

罗曼罗兰说过:世界上只有一种英雄主义,就是看清生活的真相之后依然热爱生活. 对于 Lombok 我相信大部分人都不陌生,但对于它的实现原理以及缺点却鲜为人知,而本文将会从 Lombok 的原理出发,手撸一个简易版的 Lombok,让你理解这个热门技术背后的执行原理,以及它的优缺点分析. 简介 在讲原理之前,我们先来复习一下 Lombok (老司机可以直接跳过本段看原理部分的内容). Lombok 是一个非常热门的开源项目 (https://github.com/rzwitserloot/lomb

图像的七个不变矩 可用于图像的匹配

http://blog.csdn.net/qq_18343569/article/details/46913501 图像的几何不变矩 矩特征主要表征了图像区域的几何特征,又称为几何矩, 由于其具有旋转.平移.尺度等特性的不变特征,所以又称其为不变矩.在图像处理中,几何不变矩可以作为一个重要的特征来表示物体,可以据此特征来对图像进行分类等操作. 1.     HU矩 几何矩是由Hu(Visual pattern recognition by moment invariants)在1962年提出的,

编译原理 - 1 手撸状态机词法分析器

感谢vczh轮子叔的坑了的教程,我的编译原理第一次入了个门,词法分析写完了,今后可以看看书继续往下学了. http://www.cppblog.com/vczh/archive/2014/03/02/206014.html 词法分析,就是对于一段代码,把他们分割成一个个的token,同时记录他们的行列号,丢掉不必要的信息,这个词法分析器很简单,简单的状态机就能胜任,用正则就没有自己造轮子的快感了,所以要自己手撸状态机拆token出来. 模仿vczh的语言,我的语言包括了以下要素 标识符:大小写字

Haskell手撸Softmax回归实现MNIST手写识别

Haskell手撸Softmax回归实现MNIST手写识别 前言 初学Haskell,看的书是Learn You a Haskell for Great Good, 才刚看到Making Our Own Types and Typeclasses这一章. 为了加深对Haskell的理解,便动手写了个Softmax回归.纯粹造轮子,只用了base. 显示图片虽然用了OpenGL,但是本文不会提到关于OpenGL的内容.虽说是造轮子, 但是这轮子造得还是使我受益匪浅.Softmax回归方面的内容参考

以鶸ice为例,手撸一个解释器(一)明确目标

代码地址 # HelloWorld.ice print("hello, world") 前言(废话) 其实从开始学习编译原理到现在已经有快半年的时间了,但是其间常常不能坚持看下去龙书(经常三天打鱼两天晒网,更何况每次打鱼不到半小时就累得不行又会放下书(笑)),截至到现在只勉强看完了前六章的部分,半年间其它事也没有做,其实想想上大学已经快两年了还是一事无成,知识也没有学到,不免觉得很羞愧. 暑假也要到了,这个学期马上也要结束了,临近大二结束之际,还是尝试着写一下以前想写的玩具吧,而本系列

使用Java Socket手撸一个http服务器

原文连接:使用Java Socket手撸一个http服务器 作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomcat的底层是怎么支持http服务的呢?大名鼎鼎的Servlet又是什么东西呢,该怎么使用呢? 在初学java时,socket编程是逃不掉的一章:虽然在实际业务项目中,使用这个的可能性基本为0,本篇博文将主要介绍如何使用socket来实现一个简单的http服务器功能,提供常见的get/post请求支持

php手撸轻量级开发(一)

聊聊本文内容 之前讲过php简单的内容,但是原生永远是不够看的,这次用框架做一些功能性的事情. 但是公司用自己的框架不能拿出来,用了用一些流行的框架比如tp,larveral之类的感觉太重,CI也不顺手,于是整体框架就用之前在幕客上看的这个,顺便自己手动改吧改吧,看哪不爽改哪里,一个精简的框架就出来了. 也在做java,但正是php这种能让人一眼看明白的精简的架构吸引了我,没有过多的设计和复杂的实现,整个项目就是明明白白聚焦于业务就好,怎么爽怎么来就好了. 前置的要求 具有一点php的功底.这个