首页
/ OpenCV 特征匹配实战:用 FlannBasedMatcher 与 FLANN 模块实现快速高效的特征点匹配

OpenCV 特征匹配实战:用 FlannBasedMatcher 与 FLANN 模块实现快速高效的特征点匹配

2026-09-06 18:24:48作者:吴年前Myrtle

本文以 OpenCV 官方教程文档 doc/tutorials/features/feature_flann_matcher/feature_flann_matcher.markdown 为核心骨架,结合仓库中 C++ / Java / Python 三种语言的完整示例代码,以及 featuresflann 模块的真实源码实现,系统讲解基于 FLANN 的近邻搜索式特征匹配:从距离度量与 Lowe 比率测试的原理,到 FlannBasedMatcher 的创建、knnMatch 调用与结果筛选的完整流程。读完本文,你将掌握如何在 OpenCV 中直接用 FlannBasedMatcher 接口完成"特征检测 → 描述子计算 → 快速近邻匹配 → 比率测试过滤"的标准链路,并理解其在源码层面如何把匹配委托给 flann::Index 完成高效搜索。

适用说明:本教程对应的官方标注兼容性为 OpenCV >= 3.0;本文所有源码路径均以当前仓库目录结构为准。

教程目标

本教程源自官方 OpenCV 特征匹配系列,目标是学会:

  • 使用 cv::FlannBasedMatcher(FLANN 描述子匹配器)接口;
  • 借助 flann 模块对大规模描述子集合执行快速且高效的匹配。

关于描述子来源需要特别注意:由于示例默认使用 SURF 特征,而 SURF 位于 opencv_contrib 的 xfeatures2d 模块中,因此需要安装 contrib 模块才能运行(也可以替换为 ORB、KAZE 等其他特征)。这一点在文档中有明确警示,示例代码也通过 HAVE_OPENCV_XFEATURES2D 宏做了编译期保护——当 contrib 模块缺失时,程序会输出提示信息后退出(见 SURF_FLANN_matching_Demo.cpp)。

原理:为什么需要 FLANN 这类近邻搜索

特征描述子的匹配本质

特征匹配的第一步是计算两幅图像各自的关键点描述子;第二步则是为第一幅图像中的每个描述子,在第二幅图像的描述子集合中寻找"最相似"的一个。经典浮点型描述子(SIFT、SURF 等)通常用**欧氏距离(L2 范数)**衡量相似度。

SIFT/SURF 描述子在数学本质上是局部邻域内方向梯度直方图(对 SURF 而言是 Haar 小波响应的直方图),因此除了欧氏距离,也可以使用直方图类度量,例如 χ²(卡方)距离、推土机距离(Earth Mover's Distance,EMD)等。

文档还引用了 Arandjelovic 等人提出的 RootSIFT 扩展思想:用平方根(Hellinger)核替代标准欧氏距离来衡量 SIFT 描述子之间的相似度,能够在流水线的各个阶段带来显著的性能提升。这类研究结论提醒我们:距离度量的选择本身也是匹配质量优化的一环,而不仅是匹配算法本身。

二值描述子与汉明距离

与浮点描述子不同,二值描述子(ORB、BRISK 等)用 0/1 位串表示特征,匹配时使用的是汉明距离(Hamming distance)。其计算等价于:对两个位串做异或(XOR)操作后再统计置位个数(population count):

[ d_{hamming}(a,b) = \sum_{i=0}^{n-1} (a_i \oplus b_i) ]

从暴力匹配到 FLANN

OpenCV 中默认存在两类匹配策略:暴力匹配器(BFMatcher)逐对比较每一个查询描述子与训练描述子,在大规模集合上开销可观;而 FlannBasedMatcher 则先在训练描述子集合上构建 cv::flann::Index 索引,再通过其近邻搜索方法完成匹配。

这一点在 features 模块头文件对 FlannBasedMatcher 的类注释中写得很明确(见 features.hpp):该匹配器会在训练描述子集合上训练 flann::Index 并调用其最近邻搜索方法,因此当训练集合很大时,它可能比暴力匹配更快。不过也正因 flann::Index 本身不支持掩码(mask),FlannBasedMatcher 同样不支持对描述子集合做掩码约束——这正是它与 BFMatcher 的显著差异之一。

匹配结果过滤:Lowe 比率测试与其它策略

比率测试的理论依据

直接取"最近邻"往往混入大量误匹配。Lowe 在其 SIFT 论文中提出**距离比率测试(distance ratio test)**来剔除错误匹配:对每个关键点,取出距离最近的两个匹配(最近邻与次近邻),计算两者距离之比,当该比值低于某个阈值时才判定为正确匹配。

其直觉在于:能够很好区分的匹配,其最近邻距离会显著小于次近邻距离(比值远小于 1);而模糊、歧义的匹配,两个最近邻距离接近(比值趋近于 1),难以判断真伪。下图即 SIFT 论文中"基于最近邻距离比率测试的匹配正确概率"示意,实线为正确匹配的概率密度分布,虚线为错误匹配的分布:

Lowe 最近邻距离比率测试中正确匹配与错误匹配的概率密度分布对比图

从图中可直观看到:正确匹配的距离比集中在较小区间,错误匹配则向 1 靠拢,因此设定阈值(示例取 0.7)即可显著剔除误匹配。

其它可选的补充过滤

文档同时给出两类备选/补充的过滤思路:

  • 交叉检验(cross check test):若特征 f_b 是 f_a 在图像 I_b 中的最佳匹配,且 f_a 也是 f_b 在 I_a 中的最佳匹配,才认定 (f_a, f_b) 为"好匹配"。在 features 模块中,BFMatcher::createcrossCheck 参数即可开启该行为(见 features.hpp),但其类注释同样说明,该技术与比率测试互为替代方案,通常能取得最少离群点的结果。
  • 几何校验(geometric test):剔除不符合几何模型(如对平面物体使用 RANSAC 鲁棒单应估计)的匹配。这正是本教程的后续篇章 Feature Homography 教程 的主题。

示例代码与运行数据

教程提供了三种语言的完整示例,位于仓库以下路径:

示例默认输入图片为仓库 samples 数据目录下的 box.png(目标物体)与 box_in_scene.png(包含该物体的场景图),均位于 samples/data。三份代码统一通过命令行解析器接收图片路径参数,C++ 端支持 --input1--input2--help(见 SURF_FLANN_matching_Demo.cpp),并在读图失败时打印用法后退出,运行示例形如:

./SURF_FLANN_matching_Demo --input1=box.png --input2=box_in_scene.png

Python 端等价写法:

python SURF_FLANN_matching_Demo.py --input1=box.png --input2=box_in_scene.png

完整 C++ 代码

#include <iostream>
#include "opencv2/core.hpp"
#ifdef HAVE_OPENCV_XFEATURES2D
#include "opencv2/highgui.hpp"
#include "opencv2/features.hpp"
#include "opencv2/xfeatures2d.hpp"

using namespace cv;
using namespace cv::xfeatures2d;
using std::cout;
using std::endl;

const char* keys =
    "{ help h |                  | Print help message. }"
    "{ input1 | box.png          | Path to input image 1. }"
    "{ input2 | box_in_scene.png | Path to input image 2. }";

int main( int argc, char* argv[] )
{
    CommandLineParser parser( argc, argv, keys );
    Mat img1 = imread( samples::findFile( parser.get<String>("input1") ), IMREAD_GRAYSCALE );
    Mat img2 = imread( samples::findFile( parser.get<String>("input2") ), IMREAD_GRAYSCALE );
    if ( img1.empty() || img2.empty() )
    {
        cout << "Could not open or find the image!\n" << endl;
        parser.printMessage();
        return -1;
    }

    //-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
    int minHessian = 400;
    Ptr<SURF> detector = SURF::create( minHessian );
    std::vector<KeyPoint> keypoints1, keypoints2;
    Mat descriptors1, descriptors2;
    detector->detectAndCompute( img1, noArray(), keypoints1, descriptors1 );
    detector->detectAndCompute( img2, noArray(), keypoints2, descriptors2 );

    //-- Step 2: Matching descriptor vectors with a FLANN based matcher
    // Since SURF is a floating-point descriptor NORM_L2 is used
    Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED);
    std::vector< std::vector<DMatch> > knn_matches;
    matcher->knnMatch( descriptors1, descriptors2, knn_matches, 2 );

    //-- Filter matches using the Lowe's ratio test
    const float ratio_thresh = 0.7f;
    std::vector<DMatch> good_matches;
    for (size_t i = 0; i < knn_matches.size(); i++)
    {
        if (knn_matches[i][0].distance < ratio_thresh * knn_matches[i][1].distance)
        {
            good_matches.push_back(knn_matches[i][0]);
        }
    }

    //-- Draw matches
    Mat img_matches;
    drawMatches( img1, keypoints1, img2, keypoints2, good_matches, img_matches, Scalar::all(-1),
                 Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );

    //-- Show detected matches
    imshow("Good Matches", img_matches );

    waitKey();
    return 0;
}
#else
int main()
{
    std::cout << "This tutorial code needs the xfeatures2d contrib module to be run." << std::endl;
    return 0;
}
#endif

完整 Python 代码

from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse

parser = argparse.ArgumentParser(description='Code for Feature Matching with FLANN tutorial.')
parser.add_argument('--input1', help='Path to input image 1.', default='box.png')
parser.add_argument('--input2', help='Path to input image 2.', default='box_in_scene.png')
args = parser.parse_args()

img1 = cv.imread(cv.samples.findFile(args.input1), cv.IMREAD_GRAYSCALE)
img2 = cv.imread(cv.samples.findFile(args.input2), cv.IMREAD_GRAYSCALE)
if img1 is None or img2 is None:
    print('Could not open or find the images!')
    exit(0)

#-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
minHessian = 400
detector = cv.xfeatures2d_SURF.create(hessianThreshold=minHessian)
keypoints1, descriptors1 = detector.detectAndCompute(img1, None)
keypoints2, descriptors2 = detector.detectAndCompute(img2, None)

#-- Step 2: Matching descriptor vectors with a FLANN based matcher
# Since SURF is a floating-point descriptor NORM_L2 is used
matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_FLANNBASED)
knn_matches = matcher.knnMatch(descriptors1, descriptors2, 2)

#-- Filter matches using the Lowe's ratio test
ratio_thresh = 0.7
good_matches = []
for m,n in knn_matches:
    if m.distance < ratio_thresh * n.distance:
        good_matches.append(m)

#-- Draw matches
img_matches = np.empty((max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8)
cv.drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_matches, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)

#-- Show detected matches
cv.imshow('Good Matches', img_matches)

cv.waitKey()

完整 Java 代码

import java.util.ArrayList;
import java.util.List;

import org.opencv.core.Core;
import org.opencv.core.DMatch;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.core.Scalar;
import org.opencv.features.DescriptorMatcher;
import org.opencv.features.Features;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.xfeatures2d.SURF;

class SURFFLANNMatching {
    public void run(String[] args) {
        String filename1 = args.length > 1 ? args[0] : "../data/box.png";
        String filename2 = args.length > 1 ? args[1] : "../data/box_in_scene.png";
        Mat img1 = Imgcodecs.imread(filename1, Imgcodecs.IMREAD_GRAYSCALE);
        Mat img2 = Imgcodecs.imread(filename2, Imgcodecs.IMREAD_GRAYSCALE);
        if (img1.empty() || img2.empty()) {
            System.err.println("Cannot read images!");
            System.exit(0);
        }

        //-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
        double hessianThreshold = 400;
        int nOctaves = 4, nOctaveLayers = 3;
        boolean extended = false, upright = false;
        SURF detector = SURF.create(hessianThreshold, nOctaves, nOctaveLayers, extended, upright);
        MatOfKeyPoint keypoints1 = new MatOfKeyPoint(), keypoints2 = new MatOfKeyPoint();
        Mat descriptors1 = new Mat(), descriptors2 = new Mat();
        detector.detectAndCompute(img1, new Mat(), keypoints1, descriptors1);
        detector.detectAndCompute(img2, new Mat(), keypoints2, descriptors2);

        //-- Step 2: Matching descriptor vectors with a FLANN based matcher
        // Since SURF is a floating-point descriptor NORM_L2 is used
        DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);
        List<MatOfDMatch> knnMatches = new ArrayList<>();
        matcher.knnMatch(descriptors1, descriptors2, knnMatches, 2);

        //-- Filter matches using the Lowe's ratio test
        float ratioThresh = 0.7f;
        List<DMatch> listOfGoodMatches = new ArrayList<>();
        for (int i = 0; i < knnMatches.size(); i++) {
            if (knnMatches.get(i).rows() > 1) {
                DMatch[] matches = knnMatches.get(i).toArray();
                if (matches[0].distance < ratioThresh * matches[1].distance) {
                    listOfGoodMatches.add(matches[0]);
                }
            }
        }
        MatOfDMatch goodMatches = new MatOfDMatch();
        goodMatches.fromList(listOfGoodMatches);

        //-- Draw matches
        Mat imgMatches = new Mat();
        Features.drawMatches(img1, keypoints1, img2, keypoints2, goodMatches, imgMatches, Scalar.all(-1),
                Scalar.all(-1), new MatOfByte(), Features.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS);

        //-- Show detected matches
        HighGui.imshow("Good Matches", imgMatches);
        HighGui.waitKey(0);

        System.exit(0);
    }
}

public class SURFFLANNMatchingDemo {
    public static void main(String[] args) {
        // Load the native OpenCV library
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        new SURFFLANNMatching().run(args);
    }
}

关键步骤逐段解析

整个流程高度结构化,分四个阶段,三份代码逻辑完全一致,仅语言 API 表达略有差异。

Step 1:SURF 关键点检测与描述子计算

int minHessian = 400;
Ptr<SURF> detector = SURF::create( minHessian );
detector->detectAndCompute( img1, noArray(), keypoints1, descriptors1 );
detector->detectAndCompute( img2, noArray(), keypoints2, descriptors2 );
  • minHessian = 400 是 SURF 检测器的 Hessian 阈值:数值越大,检测出的关键点越"显著"、数量越少,反之则越多。
  • detectAndCompute 一步同时完成关键点检测与描述子计算,这里以灰度图 IMREAD_GRAYSCALE 读取输入。
  • 语言差异点:C++/Python 只需传 Hessian 阈值,而 Java 版 SURF.create(hessianThreshold, nOctaves, nOctaveLayers, extended, upright) 还显式列出了八度数量(4)、层数(3)、是否扩展(false)与是否直立(false),与默认构造语义一致。
  • 若未安装 contrib 的 xfeatures2d,SURF 不可用——此时可退而使用 ORB、KAZE 等 features 模块内置特征(这也是文档给出的替代方案)。

Step 2:用 FLANN 匹配器做 k 近邻匹配

Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED);
std::vector< std::vector<DMatch> > knn_matches;
matcher->knnMatch( descriptors1, descriptors2, knn_matches, 2 );

这里有两个值得展开的要点:

其一,匹配器通过工厂方法统一创建。features 模块的 matchers.cpp 中,DescriptorMatcher::create(const String&) 按名称分发:"FlannBased" 对应 makePtr<FlannBasedMatcher>()(需要 HAVE_OPENCV_FLANN 宏开启 flann 模块),"BruteForce" 等则分别对应不同范数的 BFMatcher。而枚举版工厂 DescriptorMatcher::create(DescriptorMatcher::FLANNBASED) 只是先把枚举映射成字符串再走同一套逻辑(见 matchers.cpp)。MatcherType 枚举定义在 features.hppFLANNBASED = 1BRUTEFORCE = 2BRUTEFORCE_L1 = 3BRUTEFORCE_HAMMING = 4BRUTEFORCE_HAMMINGLUT = 5BRUTEFORCE_SL2 = 6

其二,knnMatch(..., 2) 表示对每个查询描述子返回 2 个最近邻knn = 2),这一步正是为 Step 3 的 Lowe 比率测试做数据准备——因为比率需要"最近邻/次近邻"。输出 knn_matches 的每一行 knn_matches[i] 是一个含 k 个 DMatch 的数组(按距离升序排列),DMatch 携带 queryIdxtrainIdximgIdxdistance 字段。方法本身在 features.hpp 中声明。

Step 3:Lowe 比率测试过滤

const float ratio_thresh = 0.7f;
std::vector<DMatch> good_matches;
for (size_t i = 0; i < knn_matches.size(); i++)
{
    if (knn_matches[i][0].distance < ratio_thresh * knn_matches[i][1].distance)
    {
        good_matches.push_back(knn_matches[i][0]);
    }
}
  • 判定条件是 最近邻距离 < 0.7 × 次近邻距离,满足则把最近邻判定为好匹配。
  • 阈值越小,过滤越严格、保留的匹配越少但越可靠;0.7 是广泛使用的经验值。Java 版本额外判断了 rows() > 1,确保该查询点确实有 2 个近邻可供比较后再取 matches[0]matches[1],避免下标越界——这是对同一逻辑更稳健的防御性写法。

Step 4:绘制并显示匹配

drawMatches( img1, keypoints1, img2, keypoints2, good_matches, img_matches, Scalar::all(-1),
             Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
imshow("Good Matches", img_matches );
waitKey();

drawMatches 把两幅图并排绘制并把过滤后的好匹配以彩色连线标出;DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS 表示不绘制没有匹配线的孤立关键点。Scalar::all(-1) 表示连线与关键点颜色由 OpenCV 随机指定,便于区分不同匹配。Java 端对等 API 是 Features.drawMatches,Python 端是 cv.drawMatches(注意 cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS 的下划线命名风格)。

源码级剖析:FlannBasedMatcher 究竟做了什么

深入 features 模块源码可以看到 FLANN 匹配器内部真正的执行链路。

索引与搜索参数的默认值

FlannBasedMatcher 的构造函数声明(见 features.hpp):

FlannBasedMatcher( const Ptr<flann::IndexParams>& indexParams = makePtr<flann::KDTreeIndexParams>(),
                   const Ptr<flann::SearchParams>& searchParams = makePtr<flann::SearchParams>() );

即默认使用 KD-Tree 索引KDTreeIndexParams,默认 trees=4)与 SearchParams(默认 checks=32,即搜索时最多检查 32 个叶节点,数值越大越精确、耗时越高)。相关参数结构体定义在 miniflann.hpp,同文件还提供 LinearIndexParamsCompositeIndexParamsAutotunedIndexParamsHierarchicalClusteringIndexParamsKMeansIndexParamsLshIndexParams(面向二值描述子的局部敏感哈希)以及用于持久化索引的 SavedIndexParamsflann::Index 构造时默认采用 FLANN_DIST_L2 距离(miniflann.hpp),与 SURF/SIFT 浮点描述子匹配的场景相匹配。

train():构建索引

匹配前需要先训练。FlannBasedMatcher::train()matchers.cpp)会把累加的 trainDescCollection 合并为 mergedDescriptors,再据此构建 flann::Index。也就是说:索引一旦建立,后续每个查询描述子都通过该索引快速检索近邻,这正是相对 BFMatcher 提速的根本。

knnMatchImpl():近邻检索与距离转换

FlannBasedMatcher::knnMatchImpl()matchers.cpp)的实现在底层调用 flannIndex->knnSearch(queryDescriptors, indices, dists, knn, *searchParams),把搜索委托给 flann::Index::knnSearch(声明见 miniflann.hpp)。

随后 convertToDMatches()matchers.cpp)负责把搜索结果转换为标准 DMatch 结构,其中有两点实现细节值得注意:

  • 无效近邻通过负索引跳过(idx >= 0 才输出);
  • 距离类型为 CV_32F(浮点、L2 情形)时会执行 sqrt(dists.at<float>(i, j)) 得到真正的欧氏距离,而 CV_32S(整型,如 Hamming 距离情形)则原样取整数值。这解释了为什么 knnMatch 返回的 DMatch::distance 与一些直接暴露 squared-L2 的底层 FLANN 返回值存在开方差异。

掩码支持与局限

FlannBasedMatcher 的实现(isMaskSupported() 返回不支持)以及头文件类注释都确认:FLANN 匹配器不支持掩码约束匹配,根本原因在于底层 flann::Index 没有掩码能力。因此,若需要按 ROI 或连通性掩码过滤候选,应改用支持掩码的 BFMatcher

调参建议、边界与注意事项

把以上原理落到工程实践,可总结出以下实操要点:

  1. 阈值语义ratio_thresh(本示例 0.7)控制"最近邻相对于次近邻必须显著更近"的强度。追求高准确率可下调到 0.6 左右;场景模糊、关键点稀疏时可适度上调以保留更多匹配,再辅以几何校验。
  2. 描述子类型决定距离与索引:SURF/SIFT 浮点描述子走默认 KD-Tree + L2 即可;ORB/BRISK 等二值描述子按文档理论应使用汉明距离,对应 FLANN 场景通常需要切换为 LshIndexParams 类索引,并注意 flann::Index 构造时默认距离是 L2,需按描述子类型显式配置。
  3. 数据规模决定匹配器选型FlannBasedMatcher 的类注释明确其优势在于"大训练集合"。小数据集上建树开销可能超过暴力匹配的收益,直接使用 BFMatcher(L2)反而更简单;同时 FLANN 不持掩码,需要掩码时应回退 BFMatcher。
  4. Java 边界检查:Java 示例对每一行先判断 rows() > 1 再取两个近邻,这在某些关键点数量不足导致近邻不足时能防止越界,值得在 C++/Python 版本中同样保留防御。
  5. 贡献模块依赖:SURF 位于 contrib 的 xfeatures2d;未安装时程序会提示需该模块(或换用 ORB/KAZE)。

运行结果

下图是示例在 box.pngbox_in_scene.png 上执行 SURF 特征匹配、并经 Lowe 比率测试(阈值 0.7)过滤后绘制的匹配结果。左图为待匹配的目标物体,右图为包含该物体的场景,彩色连线将两幅图中彼此对应的特征点相连,过滤后保留的连线基本都对应真实对应点,错误匹配被有效抑制:

SURF 特征与 FLANN 匹配经 Lowe 比率测试过滤后的可视化结果,展示 box 目标在场景中的正确匹配连线

仓库中与本文内容配套的自动化测试也验证了同一套用法:例如 test_flann_based_matcher.py 通过 cv2.FlannBasedMatcher(index_param, search_param) 构建匹配器并调用 knnMatch(..., k=2)test_feature_homography.py 展示了"ORB 特征 + FLANN(LSH 索引)+ knnMatch"在实际跟踪管线中的应用,可作为二值描述子使用 FLANN 的参考实现。

延伸阅读

本教程是 OpenCV 特征系列的一环:上游是特征检测与描述子计算教程 feature_description,下游则在得到过滤后的匹配之后,进一步用 findHomographyperspectiveTransform 估计两图间的变换以定位已知物体,即 Feature Homography 教程,并最终扩展到 平面物体检测教程。如果你想在一个大图库/视频序列中检索目标,或为 SLAM、图像拼接(stitching)提供特征对应,掌握 FlannBasedMatcher + 比率测试 + 几何校验这条管线,就是最实用的起点。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388