C#
什么是类
类是创建对象的模版。它是包含属性和方法,我们可以从一个类中创建许多对象实例
面向对象的概念
封装、继承、抽象、多态
封装:是指将对象的状态(属性)和行为(方法)封装在类中,并控制外部对这些属性和方法的访问,通过封装,可以隐藏对象的内部实现细节、只暴露必要的接口,从而增强代码的安全性和可维护性。
继承:允许一个类从另一个类继承属性和方法,从而实现代码复用,通过继承,子类可以扩展或修改父类的行为。
抽象:是指从具体的事物中提取出共同的特征和行为,形成一个抽象的类或接口,从而简化复杂性。抽象可以通过定义抽象类或接口来实现。
多态:是指同一个方法在不同的对象上可以表现出不同的行为。多态有两种方式:编译时多态-方法重载(同一个类中同名不同参数)和运行时多态-方法重写(子类重写父类方法)来实现。
什么是对象
对象是类的实例化,是类的具体表现。它包含类定义的属性和方法,并可以通过这些属性和方法来操作数据和执行行为。
什么是构造函数,他有哪些不同的类型
构造函数就像一个与类同名的方法,但是它是唯一的方法,即使没有创建,编译器也会在创建类的对象时在类的内存中创建一个默认的构造函数。构造函数用于使用一些默认值初始化对象,默认构造函数、参数化构造函数,复制构造函数、静态构造函数和私有构造函数都是不同的构造类型。
C#中的析构函数是什么?
析构函数(Destructor)是一种特殊的函数,用于在对象生命周期结束时执行清理操作。析构函数通常在对象被垃圾回收器(Garbage Collector)回收之前调用,用来释放对象占用的非托管资源(如文件句柄、数据库连接等),而托管资源则由垃圾回收器自动处理。
C#是托管代码还是非托管代码
C#是托管代码。托管代码是指由.NET运行时(CLR)管理的代码,CLR提供了内存管理、垃圾回收、安全性等功能。非托管代码则是指直接与操作系统交互的代码,如C或C++编写的代码。
C#中的值类型和引用类型的区别
值类型直接包含数据,它们在栈(stack)上分配内存。当我们将一个值类型变量赋给另一个值类型变量时,会复制其值。因此,两个变量是完全独立的,修改其中一个不会影响另一个。
- 基本类型:int, float, double, char, bool, decimal
- 结构体(struct):用户定义的结构也是值类型
- 枚举(enum)
引用类型变量存储的是对象的引用(地址),而对象本身存储在堆(heap)上。当我们将一个引用类型变量赋给另一个引用类型变量时,实际上是复制了该对象的引用(指向同一个内存地址),因此两个变量指向同一个对象,修改其中一个变量会影响另一个变量。
- 类(class)
- 接口(interface)
- 委托(delegate)
- 数组(array)
C#中的接口是什么?它有什么作用?
接口(Interface)是一种抽象类型,它定义了一组方法、属性、事件和索引器,但不提供具体的实现。接口可以被类或结构体实现,从而强制它们提供接口中定义的方法和属性的具体实现。
接口的作用包括:
规范化:接口定义了一组规则,任何实现该接口的类都必须遵循这些规则,从而确保了不同类之间的一致性。
解耦合:通过接口,可以将接口的使用者与具体实现分离,降低了系统的耦合度,提高了灵活性和可维护性。
多态性:接口支持多态性,允许不同类的对象通过相同的接口进行交互,从而实现动态绑定。
可扩展性:接口可以方便地扩展新的实现,而不需要修改现有代码,从而提高了系统的可扩展性。
什么是命名空间,它是强制性的吗?
命名空间(Namespace)是C#中用于组织代码的机制,它允许将相关的类、接口、结构体等组织在一起,避免命名冲突。命名空间可以看作是一个容器,用于将不同的代码元素分组。 命名空间不是强制性的,但它是一个良好的编程实践。使用命名空间可以提高代码的可读性和可维护性,尤其是在大型项目中,可以有效地组织和管理代码。
用例子解释 C# 中的注释类型
C# 中有三种主要的注释类型:
- 单行注释:使用
//
开头,注释内容直到行尾。csharp// 这是一个单行注释 int x = 10; // 变量 x 的值为 10
- 多行注释:使用
/*
开头,*/
结尾,可以注释多行内容。csharp/* 这是一个多行注释 可以注释多行内容 */ int y = 20; /* 变量 y 的值为 20 */
- 文档注释:使用
///
开头,通常用于生成 XML 文档注释,可以为类、方法、属性等提供描述。csharp/// <summary> /// 这是一个文档注释示例 /// </summary>
什么是序列化?
序列化是将对象转换为可存储或传输的格式的过程。它允许将对象的状态保存到文件、数据库或网络中,以便在需要时可以重新创建该对象。反序列化是将序列化后的数据转换回对象的过程。为了便于对象进行可序列化,它应该实现 ISerialize 接口。
如何在同一个类中实现多个具有相同方法名的接口?
在 C# 中,如果一个类实现了多个接口,并且这些接口中有相同的方法名,可以通过显式接口实现来区分它们。显式接口实现允许在类中定义接口方法的具体实现,而不与类的其他成员发生冲突。
public interface IFirst
{
void Display();
}
public interface ISecond
{
void Display();
}
public class MyClass : IFirst, ISecond
{
void IFirst.Display()
{
Console.WriteLine("IFirst Display");
}
void ISecond.Display()
{
Console.WriteLine("ISecond Display");
}
}
什么是虚方法,它与抽象方法有什么不同?
虚方法(Virtual Method)是指在基类中定义的方法,可以在派生类中重写(Override)。虚方法提供了一个默认的实现,但允许派生类根据需要提供自己的实现。虚方法可以有具体的实现,也可以是空的。通过基类引用调用一个虚方法时,如果子类重写了该方法,则会调用子类的实现,而不是基类的实现。这种行为称为运行时多态。
public class BaseClass
{
public virtual void Display()
{
Console.WriteLine("BaseClass Display");
}
}
public class DerivedClass : BaseClass
{
public override void Display()
{
Console.WriteLine("DerivedClass Display");
}
}
public class Program
{
public static void Main()
{
BaseClass obj = new DerivedClass();
obj.Display(); // 输出: DerivedClass Display
BaseClass obj2 = new BaseClass();
obj2.Display(); // 输出: BaseClass Display
DerivedClass obj3 = new DerivedClass();
obj3.Display(); // 输出: DerivedClass Display
}
}
抽象方法(Abstract Method)是指在抽象类中定义的方法,没有具体的实现,必须在派生类中重写。抽象方法强制要求派生类提供具体的实现。抽象方法只能定义在抽象类中,抽象类不能实例化。抽象方法通常用于定义一个接口或协议,要求所有派生类都遵循这个协议。
public abstract class AbstractClass
{
public abstract void Display();
}
public class ConcreteClass : AbstractClass
{
public override void Display()
{
Console.WriteLine("ConcreteClass Display");
}
}
特性 | 虚方法 | 抽象方法 |
---|---|---|
定义方式 | 使用virtual 关键字 | 使用 abstract 关键字 |
实现 | 可以有具体实现,也可以为空 | 没有具体实现,必须在派生类中实现 |
派生类实现 | 可以选择重写或不重写 | 必须重写 |
类类型 | 可以定义在普通类或抽象类中 | 只能在抽象类中定义 |
实例化 | 可以实例化包含虚方法的类 | 不能实例化抽象类即使不包含抽象方法 |
virtual 就是专门为重写而设计的,C# 要求显式声明重写意图,不像 Java 等语言默认可重写。这种设计提供了更好的控制性、性能和API清晰度,没有 virtual 的方法在设计上就是"不希望被重写的"
可以在静态类中使用“this”吗?
在静态类中是不能使用“this”关键字的,因为静态类不能实例化,也就没有实例化对象的上下文。静态类中的成员是静态的,直接通过类名访问,不需要通过实例来访问。
常量和只读变量有什么区别?
常量(const)和只读变量(readonly)都是用于定义不可变的值,但它们有一些关键的区别:
特性 | 常量(const) | 只读变量(readonly) |
---|---|---|
定义方式 | 使用 const 关键字 | 使用 readonly 关键字 |
初始化 | 必须在声明时初始化,且值在编译时已确定 | 可以在声明时或构造函数中初始化,值可以在运行时确定 |
修改 | 不能在运行时修改,值在编译时固定 | 可以在构造函数中设置,但之后不能修改 |
string
和 StringBuilder
的区别
特性 | string | StringBuilder |
---|---|---|
类型 | 不可变类型(immutable) | 可变类型(mutable) |
性能 | 每次修改都会创建新的字符串对象,性能较低 | 在原有对象上修改,性能更高 |
使用场景 | 适用于少量字符串操作或不频繁修改的情况 | 适用于频繁修改字符串的情况,如拼接、插入等 |
内存分配 | 每次修改都会分配新的内存空间,可能导致内存碎片 | 在内部使用动态数组,减少内存分配次数 |
线程安全 | 不是线程安全的 | 不是线程安全的,但可以通过锁机制实现线程安全 |
什么是密封类
密封类(Sealed Class)是指不能被继承的类。在 C# 中,可以使用 sealed
关键字来声明一个密封类。密封类的主要目的是防止其他类从它派生,从而确保该类的行为不会被修改。
public sealed class SealedClass
{
public void Display()
{
Console.WriteLine("SealedClass Display");
}
}
public class DerivedClass : SealedClass // 编译错误:无法从密封类派生
{
public void Show()
{
Console.WriteLine("DerivedClass Show");
}
}
using 语句
using
语句用于在 C# 中引入命名空间或管理资源。它有两种主要用途:
- 引入命名空间:使用
using
关键字可以引入命名空间,从而可以直接使用该命名空间中的类、接口等,而不需要每次都写全名。 - 管理资源:使用
using
语句可以确保在使用完资源后自动释放它们,通常用于实现IDisposable
接口的对象。
using System;
namespace MyNamespace
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
int?和int有什么区别
int?
是 C# 中的可空类型(Nullable Type),它允许一个整数变量可以存储一个整数值或 null
。而 int
是普通的整数类型,只能存储整数值,不能存储 null
。
C#中参数传递 ref 与 out 的区别?
在 C# 中,ref
和 out
都是用于传递参数的关键字,但它们有一些重要的区别:
特性 | ref | out |
---|---|---|
初始化 | 必须在传递前初始化 | 不需要在传递前初始化 |
使用方式 | 在方法调用时需要使用 ref 关键字 | 在方法调用时需要使用 out 关键字 |
返回值 | 可以在方法中修改并返回值 | 必须在方法中赋值,且方法结束时必须赋值 |
访问修饰符的区别
修饰符 | 访问范围 |
---|---|
public | 可以在任何地方访问 |
private | 只能在类或结构体内部访问 |
protected | 只能在类或结构体及其派生类中访问 |
internal | 只能在同一程序集内访问 |
C#中的委托是什么?事件是不是一种委托
委托(Delegate)是 C# 中的一种类型,用于封装方法的引用。它允许将方法作为参数传递,或将方法赋值给变量,从而实现回调机制。委托可以看作是一个类型安全的函数指针。委托可以保存对一个或多个方法的引用,并允许在稍后调用这些方法。多播委托(Multicast Delegate)是指可以同时调用多个方法的委托。委托的实例可以通过 +=
和 -=
运算符来添加或移除方法。 委托的定义通常包括方法的签名(返回类型和参数类型),并且可以通过 delegate
关键字来声明。
public delegate void MyDelegate(string message);
public class Program
{
public static void Main(string[] args)
{
MyDelegate del = new MyDelegate(DisplayMessage);
del("Hello, World!");
}
public static void DisplayMessage(string message)
{
Console.WriteLine(message);
}
}
事件(Event)是基于委托的一种特殊机制,用于实现发布-订阅模式。事件允许一个类(发布者)向外部提供通知,而其他类(订阅者)可以订阅这些通知。事件本质上是一个委托的封装,提供了更高层次的抽象。 事件通常使用 event
关键字来声明,并且只能通过添加或移除事件处理程序来触发。事件的使用可以提高代码的可读性和可维护性。
public delegate void MyEventHandler(string message);
public class Publisher
{
public event MyEventHandler MyEvent;
public void RaiseEvent(string message)
{
MyEvent?.Invoke(message);
}
}
public class Subscriber
{
public void OnMyEvent(string message)
{
Console.WriteLine("Event received: " + message);
}
}
public class Program
{
public static void Main(string[] args)
{
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();
publisher.MyEvent += subscriber.OnMyEvent;
publisher.RaiseEvent("Hello, Event!");
}
}
CTS、CLS、CLR
- CTS(Common Type System):公共类型系统,定义了 .NET 中所有数据类型的规则和约定。它确保不同语言之间的数据类型可以互操作。
- CLS(Common Language Specification):公共语言规范,是一组规则和约定,确保不同 .NET 语言之间的代码可以互操作。CLS 是 CTS 的子集,定义了所有 .NET 语言必须遵循的基本规则。
- CLR(Common Language Runtime):公共语言运行时,是 .NET 的执行环境,负责代码的执行、内存管理、异常处理、安全性等。CLR 提供了一个统一的运行时环境,使得不同语言编写的代码可以在同一平台上运行。
什么是拆箱和装箱
装箱(Boxing)是将值类型转换为引用类型的过程。它将值类型封装在一个对象中,并分配在堆上。装箱操作会创建一个新的对象实例,并将值类型的值复制到该对象中。 拆箱(Unboxing)是将引用类型转换回值类型的过程。它从对象中提取值类型的值,并将其存储在一个值类型变量中。拆箱操作需要显式转换,并且必须确保对象实际上是一个值类型。
int number = 42; // 值类型
object boxedNumber = number; // 装箱,将值类型转换为引用类型
int unboxedNumber = (int)boxedNumber; // 拆箱,将引用类型转换回值类型
string str=null 和 string str="" 的区别
在 C# 中,string str = null;
和 string str = "";
是两个不同的概念。
string str = null;
表示str
变量没有指向任何对象,它是一个空引用。对str
进行任何操作都会引发NullReferenceException
异常。string str = "";
表示str
变量指向一个空字符串对象。虽然这个字符串没有任何字符,但它是一个有效的字符串对象,可以安全地进行操作。
类class和结构struct的异同
特性 | 类(class) | 结构(struct) |
---|---|---|
类型 | 引用类型 | 值类型 |
存储 | 存储在堆上 | 存储在栈上 |
继承 | 支持继承 | 不支持继承 |
默认构造函数 | 有默认构造函数 | 没有默认构造函数 |
适用场景 | 适用于需要继承、 polymorphism 和较大数据结构的情况 | 适用于小型数据结构,如点、矩形等 |
枚举的作用是什么
枚举(Enum)是一种特殊的值类型,用于定义一组命名的常数。它提供了一种方式来为一组相关的常量赋予有意义的名称,从而提高代码的可读性和可维护性。枚举可以用于表示状态、选项、类别等。 枚举的主要作用包括:
- 提高可读性:使用枚举可以使代码更易于理解,避免使用魔法数字或字符串。
- 类型安全:枚举提供了类型安全,确保只能使用预定义的常量值,避免了无效值的使用。
- 易于维护:如果需要添加或修改常量,只需在枚举中进行更改,而不需要在代码中查找和替换所有相关的值。
保存数据的方法
- 文本文件保存 用于保存简单的文本数据
// 写入文本文件
File.WriteAllText("data.txt", "保存的文本数据");
// 读取文本文件
string content = File.ReadAllText("data.txt");
- 二进制文件保存 适用于保存图像、音频等非文本数据
// 写入二进制文件
byte[] data = new byte[] { 0x00, 0xFF, 0xAB };
File.WriteAllBytes("data.bin", data);
// 读取二进制文件
byte[] readData = File.ReadAllBytes("data.bin");
- XML文件保存
// 创建XML文件
// 实例化xml对象
XmlDocument xmlDocument = new XmlDocument();
// 设置第一行数据
XmlDeclaration xmlDeclaration = xmlDocument.CreateXmlDeclaration("1.0", "utf-8", null);
// 将第一行数据添加
xmlDocument.AppendChild(xmlDeclaration);
// 创建xml文件根节点
XmlElement root = xmlDocument.CreateElement("root");
// 将根节点添加
xmlDocument.AppendChild(root);
// 保存数据
xmlDocument.Save("file.xml");
// 读取XML文件
public static XmlNodeList LoadFileList(string path)
{
// 实例化xml文件对象
XmlDocument xmlDocument = new XmlDocument();
// 根据文件路径加载xml文件
xmlDocument.Load(path);
// 获取xml文件根节点
XmlElement root = xmlDocument.DocumentElement;
// 返回xml文件根节点的子节点
return root.ChildNodes;
}
数据库保存 使用关系型数据库(如 SQL Server、MySQL)或非关系型数据库(如 MongoDB)来存储数据。
配置文件保存 config 文件常用于保存应用程序的配置信息,通常在 ASP.NET 或桌面应用程序中使用。
内存存储 将数据保存在内存中,如使用集合(List、Dictionary 等)或缓存(如 MemoryCache)。
多线程访问资源的问题
多线程环境下,当多个线程同时访问共享资源时,可能会出现多种问题,影响程序的正确性和性能。
- 数据竞争(Data Race)
- 问题描述:多个线程同时对共享资源进行读写操作,没有同步机制的保护,每个线程操作可能会互相覆盖,导致最终数据不准确。
- 后果:数据不一致、程序结果不可预测
- 死锁(Deadlock)
- 问题描述:两个或多个线程相互等待对方释放资源,导致程序卡住,无法继续执行。例如,线程A持有资源1等待资源2,线程B持有资源2等待资源1。
- 后果:程序永久阻塞,无法继续执行
- 资源争用(Resource Contention)
- 问题描述:多个线程尝试同时访问某个资源,导致系统性能下降。常见的资源争用包括多个线程同时读写同一个文件、数据库记录、内存块等。
- 后果:系统响应时间变长,处理效率降低
- 饥饿(Starvation)
- 问题描述:某些线程由于系统调度策略或资源分配问题,长期得不到执行机会,导致其无法完成工作。
- 后果:低优先级线程长期无法获取资源,影响系统公平性
- 活锁(Livelock)
- 问题描述:线程不断地重复尝试某个操作(通常是为了避开死锁),但总是失败,导致程序无法继续执行。
- 后果:CPU资源浪费,程序无法取得进展
- 数据不一致性
- 问题描述:在没有适当同步的情况下,多个线程同时读取和修改共享数据会导致数据处于错误的中间状态。
- 后果:数据完整性被破坏,业务逻辑错误
解决方案
- 锁(Lock) 使用
lock
关键字来确保同一时间只有一个线程可以访问共享资源,从而避免数据竞争。
private static readonly object _lock = new object();
public void UpdateResource()
{
lock (_lock)
{
// 访问和修改共享资源
}
}
- 互斥量(Mutex) 使用
Mutex
类来实现跨进程的同步,确保同一时间只有一个线程可以访问共享资源。
Mutex mutex = new Mutex();
public void UpdateResource()
{
mutex.WaitOne(); // 等待获取互斥量
try
{
// 访问和修改共享资源
}
finally
{
mutex.ReleaseMutex(); // 释放互斥量
}
}
- 信号量(Semaphore) 限制对共享资源的并发访问数量,适用于资源争用问题。
private static Semaphore semaphore = new Semaphore(3, 3); // 最多允许3个线程同时访问
public void AccessResource()
{
semaphore.WaitOne(); // 等待信号量
try
{
// 访问共享资源
}
finally
{
semaphore.Release(); // 释放信号量
}
}
- 读写锁(ReaderWriterLockSlim) 用于解决读写操作之间的冲突,允许多个线程同时读取数据,但写操作需要独占锁。
private static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
public void ReadData()
{
rwLock.EnterReadLock();
try
{
// 读取数据
}
finally
{
rwLock.ExitReadLock();
}
}
public void WriteData()
{
rwLock.EnterWriteLock();
try
{
// 写入数据
}
finally
{
rwLock.ExitWriteLock();
}
}
- 线程安全集合 使用 .NET 提供的线程安全集合类来管理共享数据,这些集合内部已经处理了线程同步问题。
// 使用线程安全的字典
ConcurrentDictionary<string, int> concurrentDict = new ConcurrentDictionary<string, int>();
// 使用阻塞集合
BlockingCollection<string> blockingCollection = new BlockingCollection<string>();
- 任务同步原语 使用更高级的同步原语来协调线程间的执行。
// 使用 ManualResetEvent 进行线程同步
private static ManualResetEvent resetEvent = new ManualResetEvent(false);
// 使用 CountdownEvent 等待多个操作完成
private static CountdownEvent countdown = new CountdownEvent(5);
C#的多线程通常有哪些类型
Thread 类 ThreadPool 线程池 Task 类 async 和 await 异步编程
线程的生命周期
线程的生命周期包括以下几个状态:
- 新建状态(New):线程被创建,但尚未开始执行。
- 就绪状态(Ready):线程已准备好执行,但尚未获得 CPU 时间片。
- 运行状态(Running):线程正在执行代码。
- 阻塞状态(Blocked):线程等待某个条件或资源(如锁、I/O 操作等),无法继续执行。
- 死亡状态(Dead):线程执行完毕或被终止,无法再执行。
线程与进程的区别
特性 | 线程(Thread) | 进程(Process) |
---|---|---|
定义 | 线程是进程中的一个执行单元,是程序执行的最小单位 | 进程是操作系统分配资源的基本单位,是一个正在运行的程序 |
内存空间 | 线程共享同一进程的内存空间 | 每个进程有独立的内存空间 |
创建开销 | 创建和销毁线程的开销较小 | 创建和销毁进程的开销较大 |
通信方式 | 线程间通信较简单,可以直接访问共享数据 | 进程间通信较复杂,需要使用 IPC(进程间通信)机制 |
调度 | 线程调度由操作系统管理,线程可以在同一进程内切换 | 进程调度由操作系统管理,进程之间的切换开销较大 |
单线程和多线程的区别
特性 | 单线程(Single Thread) | 多线程(Multi Thread) |
---|---|---|
定义 | 只有一个线程执行任务 | 有多个线程同时执行任务 |
执行方式 | 任务按顺序执行,一个接一个 | 任务可以并发执行,多个线程同时工作 |
资源利用 | 资源利用率较低,无法充分利用多核 CPU | 资源利用率较高,可以充分利用多核 CPU |
响应性 | 响应性较差,长时间任务会阻塞其他操作 | 响应性较好,可以在一个线程中执行长时间任务而不阻塞其他操作 |
内存泄漏
内存泄漏是指程序在运行过程中分配了内存但未能正确释放,导致内存无法被回收,从而逐渐耗尽系统资源。内存泄漏会导致程序性能下降、响应变慢,甚至崩溃。 内存泄漏通常发生在以下情况:
- 未释放托管资源:虽然 .NET 的垃圾回收器会自动管理托管资源,但如果使用了非托管资源(如文件句柄、数据库连接等),需要手动释放。
- 事件订阅未取消:如果一个对象订阅了另一个对象的事件,但在不再需要时没有取消订阅,可能导致被订阅的对象无法被垃圾回收。
- 静态引用:使用静态变量或字段持有对象的引用,可能导致这些对象无法被垃圾回收。
- 长生命周期对象对短生命周期对象的引用:如果一个长生命周期的对象持有短生命周期对象的引用,可能导致短生命周期对象无法被垃圾回收。
- 循环引用:两个或多个对象互相引用,导致垃圾回收器无法识别它们不再被使用。
- 集合类未清空:使用集合类(如 List、Dictionary 等)存储对象时,如果未清空集合,可能导致对象无法被垃圾回收。
- Timer、线程池等未正确释放:使用定时器、线程池等资源时,如果未正确释放,可能导致内存泄漏。需要在不再需要时停止定时器或线程池任务,并显式调用 Dispose 方法释放相关资源。
SDK
SDK(Software Development Kit)是软件开发工具包,通常包含一组用于特定平台或框架的开发工具、库、文档和示例代码。SDK 旨在帮助开发人员更轻松地构建应用程序或服务,提供了必要的 API、工具和资源,使得开发过程更加高效。
联合编程使用的什么协议(通信协议)?
这取决于具体的联合编程(例如与 PLC、机器人或其他软件系统)的设备和场景。
- 通用协议:
- 网络通信:TCP/IP (更可靠,面向连接)、UDP (更快,无连接)。常用于需要通过局域网或互联网通信的场景。
- 串口通信:RS232、RS485 等。常用于直接连接设备,距离较近的场景。
- 特定厂商/工业协议:
- 西门子 PLC:常用 S7 Communication 协议 (基于 TCP/IP)。可以使用 S7.Net 或 Sharp7 等库进行 C# 编程。
- Modbus:Modbus TCP (基于 TCP/IP)、Modbus RTU/ASCII (基于串口)。广泛用于工业设备。
- 欧姆龙 PLC:FINS 协议,通常用于欧姆龙设备的通信。
- OPC UA:一种跨平台的工业自动化标准,安全性和互操作性好。
- 其他:EtherNet/IP, Profinet 等。
- Web 服务/API:
- HTTP/HTTPS:使用 RESTful API 或 SOAP。常用于与其他软件系统或 Web 服务集成。
关键点:需要根据通信对方的要求和网络环境选择合适的协议和相应的 C# 库。如果是西门子,S7 Net 通过网口使用 S7 协议是常见方案。
C# 中常用的通信库 HslCommunication
HslCommunication 是一个开源的 C# 通信库,提供了多种工业协议的支持,包括 Modbus、OPC UA、S7 等。它旨在简化工业设备与 C# 应用程序之间的通信。 HslCommunication 的主要特点包括:
- 多协议支持:支持多种工业通信协议,如 Modbus TCP/RTU、OPC UA、S7、Siemens 等。
- 易于使用:提供了简单易用的 API,开发人员可以快速集成到 C# 应用程序中。
- 高性能:优化了通信性能,适用于实时数据采集和控制。
- 开源:HslCommunication 是一个开源项目,开发人员可以自由使用和修改代码。
Modbus 协议
Modbus 是一种工业通信协议,由 Modicon(施耐德电气)开发,广泛用于连接工业设备和控制系统。它允许主设备(如 PLC、计算机)与从设备(如传感器、执行器)进行数据交换。 Modbus 协议有主要变体:
- Modbus RTU:基于串口通信,使用二进制格式,适用于短距离通信。
- Modbus TCP:基于以太网,使用 TCP/IP 协议,适用于长距离通信。
- Modbus ASCII:基于串口通信,使用 ASCII 字符格式,适用于需要人类可读的通信。
override与重载的区别?
- 重载 (Overload):指在同一个类中,可以有多个同名的方法,但它们的参数列表必须不同(参数个数、类型或顺序不同)。返回类型不能作为区分重载的依据。重载是一种编译时的多态性。
- 目的:提供多种方式来调用具有相似功能但处理不同输入的方法。
- 重写 (Override):指在子类中重新实现一个在基类中被标记为
virtual
、abstract
或override
的同名同签名的方法。重写是实现运行时多态性 (Polymorphism) 的关键。- 目的:让子类能够提供特定于自身的实现,替换基类的行为。
请手写一个冒泡排序算法
/// <summary>
/// 对整数数组进行冒泡排序 (升序)
/// </summary>
/// <param name="array">需要排序的数组</param>
public static void BubbleSort(int[] array)
{
// 健壮性检查: 处理 null 或空数组的情况
if (array == null || array.Length <= 1)
{
return;
}
int n = array.Length;
int temp = 0;
bool swapped; // 优化: 如果一轮没有发生交换,说明已经有序
// 外层循环: 控制排序的轮数,最多 n-1 轮
for (int i = 0; i < n - 1; i++)
{
swapped = false;
// 内层循环: 进行相邻元素的比较和交换
// 注意边界: j < n - 1 - i,因为每轮最大的元素会沉到末尾,无需再比较
for (int j = 0; j < n - 1 - i; j++)
{
// 比较: 如果前一个元素大于后一个元素
if (array[j] > array[j + 1])
{
// 交换
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
swapped = true; // 标记发生了交换
}
}
// 优化: 如果在本轮没有发生任何交换,则数组已经完全排序,可以提前退出
if (!swapped)
{
break;
}
}
}
// 示例用法:
int[] numbers = new int[] { 9, 2, 8, 4, 6, 1, 7, 3, 5 }; // 修正了原数组初始化语法
Console.WriteLine("Original array: " + string.Join(", ", numbers));
BubbleSort(numbers);
Console.WriteLine("Sorted array: " + string.Join(", ", numbers));
描述一下C#中索引器的实现过程,是否只能根据数字进行索引?
实现过程: 索引器 (Indexer) 允许类的实例像数组一样使用 []
语法进行访问。它通过在类或结构中定义一个名为 this
的特殊属性来实现。
public class MyCollection<T>
{
private T[] data = new T[100]; // 内部存储
// 索引器定义: 使用 this 关键字,指定索引类型和返回值类型
public T this[int index] // 这里索引类型是 int
{
get
{
// 获取访问器: 返回指定索引处的数据
if (index < 0 || index >= data.Length)
throw new IndexOutOfRangeException("Index out of range");
return data[index];
}
set
{
// 设置访问器: 设置指定索引处的数据
if (index < 0 || index >= data.Length)
throw new IndexOutOfRangeException("Index out of range");
data[index] = value; // value 是隐式参数,表示赋给索引器的值
}
}
// 可以重载索引器: 使用不同类型的索引
public T this[string name] // 这里索引类型是 string
{
get { /* 根据名称查找并返回值 */ throw new NotImplementedException(); }
set { /* 根据名称设置值 */ throw new NotImplementedException(); }
}
}
// 用法:
MyCollection<string> collection = new MyCollection<string>();
collection[0] = "Hello"; // 使用 int 索引
string value = collection[0];
// collection["name"] = "World"; // 使用 string 索引 (如果实现了的话)
是否只能根据数字进行索引?
不是。索引器的索引类型可以是任何类型,例如 int
, string
, enum
或其他自定义类型。可以重载索引器以支持多种不同的索引类型。
什么叫应用作用域?
"应用作用域 (Application Scope)" 不是 C# 或 .NET 中一个标准的、广泛使用的术语来描述变量可见性或生命周期管理(像 private
/public
定义作用域,或者像 using
语句管理生命周期那样)。
这个术语可能指代以下几种可能相关的概念,具体含义取决于上下文:
- 依赖注入 (DI) 中的作用域 (Scope):在现代 .NET 应用 (尤其是 ASP.NET Core) 中,服务注册时可以指定作用域:
- Singleton:整个应用程序生命周期内只有一个实例。
- Scoped:在某个特定的请求或操作单元(如 Web 请求)内只有一个实例。
- Transient:每次请求时都创建一个新的实例。 这符合“轻量级”、“安全”(隔离请求)、“占用资源”(Singleton 最省资源,Transient 最耗资源)的描述。
- 应用程序域 (Application Domain):这是 .NET Framework 中的一个较旧的概念(在 .NET Core/5+ 中作用减弱),它提供进程内的隔离单元,可以加载和卸载程序集,起到一定的安全隔离作用。这与“安全”、“占用资源”有关,但通常不被认为是“轻量级”的。
- 变量的作用域 (Scope):指变量可以被访问的代码区域(如块作用域
{}
、方法作用域、类作用域)。但这通常不称为“应用作用域”。
总结:如果面试中遇到此问题,最好反问面试官,请其澄清“应用作用域”的具体含义或询问是否指依赖注入中的服务生命周期/作用域。原始答案中的描述最接近依赖注入的概念。
堆和栈的区别是什么?
在 C#/.NET 的上下文中:
- 栈 (Stack):
- 用于存储值类型变量(如
int
,bool
,struct
实例,除非它们是类的成员)、方法参数、局部变量以及方法调用的上下文信息(返回地址等)。 - 内存管理由编译器自动完成。当方法进入时,参数和局部变量被压入栈;当方法退出时,它们被自动弹出(释放)。
- 特点:分配速度快、内存空间有限、后进先出 (LIFO) 数据结构。
- 每个线程都有自己独立的栈。
- 用于存储值类型变量(如
- 堆 (Heap):
- 用于存储引用类型的实例(如
class
的对象、string
、数组)以及值类型被装箱 (Boxing) 后的数据。 - 内存管理主要由垃圾收集器 (GC) 负责。程序员使用
new
关键字在堆上分配内存,GC 会自动回收不再被引用的对象所占用的内存。 - 特点:分配速度相对较慢、内存空间较大(受限于可用物理内存和虚拟内存)、内存管理复杂(由 GC 处理,可能导致性能暂停)。
- 堆内存由进程中的所有线程共享。
- 用于存储引用类型的实例(如
关键区别:存储内容 (值类型/局部变量 vs 引用类型/对象)、内存管理方式 (自动 LIFO vs GC)、分配速度、生命周期、线程关系 (线程私有 vs 进程共享)。
什么是虚函数?什么是抽象函数?
两者都与继承和多态相关。
- 虚函数 (Virtual Function):
- 在基类中使用
virtual
关键字声明的方法。 - 虚函数必须有方法体(提供默认实现)。
- 子类可以使用
override
关键字重写 (Override) 该方法,提供自己的实现。如果子类不重写,则继承基类的实现。 - 目的是允许子类在需要时改变基类的行为,实现多态。
- 示例:csharp
public class Animal { public virtual void MakeSound() { Console.WriteLine("Some generic sound"); } } public class Dog : Animal { public override void MakeSound() { Console.WriteLine("Bark"); } }
- 在基类中使用
- 抽象函数 (Abstract Function):
- 在抽象类 (Abstract Class) 中使用
abstract
关键字声明的方法。 - 抽象函数没有方法体(只有声明,没有实现),以分号结束。
- 声明抽象函数的类必须也声明为
abstract
类。 - 任何非抽象的子类都必须使用
override
关键字实现 (重写) 基类中的所有抽象方法。 - 目的是强制子类提供特定的实现,定义一个必须遵循的契约,同时不允许创建基类(抽象类)的实例。
- 示例:csharp
public abstract class Shape { public abstract double CalculateArea(); // 没有实现 } public class Circle : Shape { public double Radius { get; set; } public override double CalculateArea() { return Math.PI * Radius * Radius; } // 必须实现 }
- 在抽象类 (Abstract Class) 中使用
关键区别:虚函数有实现、可以被重写;抽象函数无实现、必须在非抽象子类中被重写,且只能在抽象类中声明。
委托声明的关键字是?
delegate
示例:
// 声明一个委托类型,它可以指向任何 T Func(T arg) 形式的方法
public delegate T MyGenericDelegate<T>(T arg);
// 声明一个委托类型,它可以指向任何 void Func(string message) 形式的方法
public delegate void LogHandler(string message);
什么是GRR?什么是CPK?
这两个术语通常出现在制造和质量管理领域,尤其是在与测量系统和过程能力相关的场景中。
- GRR (Gage Repeatability and Reproducibility):测量系统重复性与再现性。
- 是一种统计方法,用于评估测量系统(Gage)的变异性(或说精度)。它分析测量结果的总变异中有多少是由测量系统本身引入的。
- 重复性 (Repeatability):指同一个操作员使用同一个测量仪器,对同一个零件的同一个特性进行多次测量时,测量结果的变异。也称为设备变异 (EV)。
- 再现性 (Reproducibility):指不同的操作员使用同一个测量仪器,对同一个零件的同一个特性进行测量时,不同操作员测量均值之间的变异。也称为评价人变异 (AV)。
- 目的:判断测量系统是否可靠,能否区分产品的好坏,其误差相对于过程变异或公差来说是否足够小。通常要求 GRR 值小于 10% 才算优秀,小于 30% 可能被接受。
- CPK (Process Capability Index):过程能力指数。
- 是一种衡量过程能力的统计指标,用于评估一个稳定的生产过程满足规格要求 (Specification Limits) 的能力。
- 它同时考虑了过程的中心位置 (均值) 是否靠近规格中心,以及过程的变异程度 (标准差) 是否足够小。
- 计算:Cpk = min [ (USL - μ) / 3σ, (μ - LSL) / 3σ ],其中 USL 是规格上限,LSL 是规格下限,μ 是过程均值,σ 是过程标准差。
- 目的:判断生产过程是否有能力持续稳定地生产出符合要求的产品。通常要求 Cpk 值大于 1.33 或 1.67(取决于行业和客户要求),数值越大表示过程能力越强。
关系:GRR 关注的是“测量工具”本身好不好用,CPK 关注的是“生产过程”本身稳不稳定、能不能满足要求。一个准确的测量系统 (好的 GRR) 是进行有效过程能力分析 (计算 CPK) 的前提。
GC是什么?为什么要有GC?
- GC (Garbage Collector):垃圾收集器。
- 是 .NET CLR (公共语言运行时) 的一个核心组件。
- 它的主要职责是自动管理内存,特别是回收那些不再被应用程序引用的对象所占用的托管堆 (Managed Heap) 内存。
- 为什么要有 GC?
- 简化内存管理:程序员不需要手动编写代码来分配和释放内存(像 C++ 中的
new
/delete
或malloc
/free
)。这大大降低了编程的复杂性。 - 防止内存泄漏 (Memory Leaks):手动管理内存时,很容易忘记释放不再使用的内存,导致内存泄漏,最终可能耗尽系统资源。GC 通过自动检测和回收不可达对象,有效防止了这类问题。
- 防止悬空指针 (Dangling Pointers):手动管理内存时,可能释放了内存后,仍有指针指向该已释放区域,访问这些指针会导致未定义行为。GC 确保只有在没有任何活动引用指向对象时才回收它,避免了悬空指针。
- 提高开发效率和程序稳定性:开发者可以将更多精力集中在业务逻辑上,而不是繁琐且易错的内存管理细节,从而提高生产力并减少因内存错误导致程序崩溃的可能性。
- 简化内存管理:程序员不需要手动编写代码来分配和释放内存(像 C++ 中的
注意:在 C# 中,虽然可以通过 GC.Collect()
建议 GC 进行回收,但这通常不推荐,因为 GC 的算法通常能更有效地决定何时进行回收。频繁手动调用可能反而降低性能。
string S = new String("ABC");创建了几个string Object?
这个问题在不同的语言和上下文中可能有细微差别,但在典型的 C#/.NET 环境下:
"ABC"
:这是一个字符串字面量 (string literal)。在编译时,编译器通常会将字符串字面量放入一个称为字符串拘留池 (String Intern Pool) 的内部表中。如果池中已存在相同内容的字符串,则会复用该实例;如果不存在,则会创建一个新的字符串对象放入池中。new String("ABC")
:这里的new
关键字显式要求创建一个新的String
对象实例在托管堆 (Heap) 上。即使拘留池中已经存在内容为 "ABC" 的字符串,new String(...)
通常也会在堆上创建一个独立的新对象,其内容与 "ABC" 相同。
结论:执行 string S = new String("ABC");
这行代码:
"ABC"
字面量可能会导致在字符串拘留池中创建或复用一个对象。new String(...)
明确地在托管堆上创建了一个新的String
对象实例。
所以,严格来说,这行代码直接导致在堆上创建了 1 个新的 String 对象 (通过 new
)。至于拘留池中的对象是否因此创建,取决于编译时池中是否已存在 "ABC"。
常见的面试回答倾向于:这行代码创建了一个或两个对象。
- 一个对象:指由
new
关键字显式创建在堆上的那个对象。 - 两个对象:指由
new
创建的堆对象 + 可能在字符串拘留池中创建(或已存在)的字面量对象。
更精确的回答:明确创建了 1 个位于堆上的新 String 对象。字符串字面量 "ABC"
对应的对象可能已存在于拘留池中,也可能在此过程中被加入池中。变量 S
将引用那个通过 new
创建的堆对象。
启动一个线程是用run()还是start()?
在 C# System.Threading.Thread
类中,启动一个新线程执行其任务,应该调用 Start()
方法。
Start()
:- 使操作系统创建一个新的线程。
- 安排这个新线程开始执行你在创建
Thread
对象时指定的委托(通常是一个方法)。 Start()
方法会立即返回,允许调用线程继续执行,而新线程则并发执行。
Run()
:- C# 的
Thread
类没有名为Run()
的公共方法用于启动线程(这更像是 Java 中的概念)。 - 如果你在委托中定义的方法恰好叫
Run
,那么Start()
会在新线程上执行这个Run
方法。但Run
本身不是启动线程的命令。 - 如果直接调用那个委托方法(比如
myDelegate.Invoke()
或myDelegate()
),它只会在当前调用线程上同步执行,并不会创建和启动新线程。
- C# 的
结论:使用 Start()
来异步启动新线程。
怎么设置线程为后台线程
在 C# 中,可以通过设置 Thread
对象的 IsBackground
属性来将线程设置为后台线程。后台线程在所有前台线程结束后会自动终止。
using System;
using System.Threading;
class Program
{
static void Main()
{
Thread backgroundThread = new Thread(DoWork);
backgroundThread.IsBackground = true; // 设置为后台线程
backgroundThread.Start();
Console.WriteLine("Main thread is doing some work...");
Thread.Sleep(2000); // 模拟主线程工作
Console.WriteLine("Main thread is exiting...");
}
static void DoWork()
{
while (true)
{
Console.WriteLine("Background thread is working...");
Thread.Sleep(1000); // 模拟后台线程工作
}
}
}
C#的异步编程的实现
C# 的异步编程主要通过 async
和 await
关键字实现,结合 Task
类来处理异步操作。以下是一些关键点和示例:
async
关键字:用于标记一个方法为异步方法。异步方法可以包含await
表达式。await
关键字:用于等待一个异步操作完成。它会暂停当前方法的执行,直到异步操作完成,然后继续执行后续代码。Task
类:表示一个异步操作。可以使用Task.Run
来启动一个新的异步任务。
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Starting async operation...");
await PerformAsyncOperation();
Console.WriteLine("Async operation completed.");
}
static async Task PerformAsyncOperation()
{
// 模拟一个异步操作,例如网络请求或文件 I/O
await Task.Delay(2000); // 等待 2 秒
Console.WriteLine("Performing async work...");
}
}
接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承实体类(concrete class)?
- 接口是否可继承接口?
- 是。一个接口可以继承一个或多个其他接口。当一个类实现了一个继承了其他接口的接口时,它必须实现所有继承链上的接口所定义的所有成员。
- 示例:csharp
interface IReadable { void Read(); } interface IWriteable { void Write(); } interface IReadWriteable : IReadable, IWriteable { } // IReadWriteable 继承了 IReadable 和 IWriteable
- 抽象类是否可实现(implements)接口?
- 是。抽象类可以实现一个或多个接口。
- 抽象类可以选择:
- 为接口成员提供具体实现。
- 将接口成员声明为抽象 (abstract),将实现的责任推迟到其非抽象子类。
- 示例:csharp
interface ILog { void Log(string message); } public abstract class LoggerBase : ILog // 抽象类实现接口 { public abstract void Log(string message); // 可以将接口方法声明为抽象 public void LogInfo(string message) { Log("INFO: " + message); } // 也可以有具体方法 }
- 抽象类是否可继承实体类(concrete class)?
- 是。抽象类可以继承一个普通(非抽象)的实体类。它也可以继承另一个抽象类。C# 只支持单继承(对于类)。
- 示例:csharp
public class ConfigurationBase { /* ... */ } public abstract class AdvancedConfiguration : ConfigurationBase // 抽象类继承实体类 { public abstract void ApplyAdvancedSettings(); }
构造器Constructor是否可被override?
否。构造器 (Constructor) 不能被标记为 virtual
、abstract
或 override
,因此它们不能被重写 (override)。
- 构造器不是普通意义上的成员,它们负责初始化对象。
- 继承链中的每个类都有自己的构造器,负责初始化该类定义的成员。
- 子类的构造器可以(并且通常会隐式或显式地)调用其基类的构造器,使用
base(...)
关键字来实现,但这不是重写,而是调用链。
示例:
public class BaseClass
{
public BaseClass(int x) { /* ... */ }
}
public class DerivedClass : BaseClass
{
// 必须调用基类的构造器
public DerivedClass(int x, int y) : base(x) // 使用 base 调用基类构造器
{
// 初始化 DerivedClass 的成员
}
// 不能 override BaseClass 的构造器
// public override BaseClass(int x) { } // 这是非法的
}
C#和C++的区别是什么?
这是一个很宽泛的问题,以下是一些关键区别:
特性 | C# | C++ |
---|---|---|
内存管理 | 自动垃圾回收 (GC) | 手动管理 (new /delete , malloc /free ), RAII, 智能指针 |
平台依赖性 | 基于 .NET Runtime (CLR),跨平台 (.NET Core/5+) | 编译为本地机器码,高度可移植但需为各平台重新编译 |
指针 | 默认不支持直接指针操作,需在 unsafe 上下文中使用 | 原生支持指针,是核心特性 |
多重继承 | 不支持类的多重继承,支持接口的多重实现 | 支持类的多重继承 (带来复杂性,如菱形继承问题) |
编译 | 编译到 中间语言 (IL),运行时由 CLR JIT/AOT 编译 | 直接编译到机器码 |
异常处理 | 强制使用结构化异常处理 (try-catch-finally ) | 支持异常处理,但也常用返回码等方式 |
类型系统 | 强类型,统一类型系统 (CTS),基于 System.Object | 强类型,但类型系统不如 C# 统一,模板提供泛型编程 |
标准库 | 丰富的基类库 (BCL)/.NET SDK | 标准模板库 (STL),相对 BCL 范围较小 |
安全性 | 内存安全(由 CLR 保证,除非用 unsafe ),类型安全 | 不保证内存安全,容易出现缓冲区溢出、悬空指针等问题 |
面向对象 | 纯面向对象(几乎所有东西都是对象) | 支持面向对象,但也支持过程式和泛型编程 |
互操作性 | 通过 P/Invoke 或 COM Interop 与本地代码交互 | 可以直接调用 C API,与其他语言交互相对直接 |
应用领域 | Web 开发 (ASP.NET), Windows 应用, 游戏 (Unity), 企业应用 | 系统编程, 游戏引擎, 高性能计算, 嵌入式系统 |
多态是什么?举例说明
多态 (Polymorphism),字面意思是“多种形态”。在面向对象编程中,它指的是不同类的对象可以响应相同的消息(方法调用),但各自表现出符合自身特征的行为。
核心思想:允许你使用基类或接口的引用来引用子类或实现类的对象,并在运行时根据对象的实际类型来决定调用哪个具体的方法实现。
实现方式:主要通过继承和方法重写 (Override)(针对虚方法或抽象方法)或接口实现来实现。
举例说明:
假设我们有一个图形 (Shape) 的概念,不同的图形计算面积的方式不同。
定义基类和虚方法:
csharp// 基类 Shape public abstract class Shape // 使用抽象类更合适,因为 Shape 本身没有具体面积 { // 定义一个抽象方法,强制子类实现 public abstract double CalculateArea(); // 也可以有非抽象/虚方法或属性 public string Name { get; protected set; } = "Generic Shape"; }
定义子类并重写方法:
csharp// 子类 Circle public class Circle : Shape { public double Radius { get; set; } public Circle(double radius) { Name = "Circle"; Radius = radius; } // 重写基类的抽象方法,提供 Circle 的面积计算方式 public override double CalculateArea() { return Math.PI * Radius * Radius; } } // 子类 Rectangle public class Rectangle : Shape { public double Width { get; set; } public double Height { get; set; } public Rectangle(double width, double height) { Name = "Rectangle"; Width = width; Height = height; } // 重写基类的抽象方法,提供 Rectangle 的面积计算方式 public override double CalculateArea() { return Width * Height; } }
演示多态:
csharppublic class DrawingApp { public void PrintShapeArea(Shape shape) // 关键: 参数类型是基类 Shape { // 多态发生在这里: 调用 CalculateArea() 时, // 实际执行的是 shape 变量所引用的 真实对象类型 (Circle 或 Rectangle) 的那个重写方法 double area = shape.CalculateArea(); Console.WriteLine($"The area of the {shape.Name} is: {area}"); } public void RunExample() { // 创建不同子类的对象 Shape circle = new Circle(5); Shape rectangle = new Rectangle(4, 6); // 使用基类引用调用同一个方法 PrintShapeArea PrintShapeArea(circle); // 输出 Circle 的面积 PrintShapeArea(rectangle); // 输出 Rectangle 的面积 // 也可以放在一个列表中 List<Shape> shapes = new List<Shape> { new Circle(2), new Rectangle(3, 5), new Circle(1) }; foreach (Shape s in shapes) { PrintShapeArea(s); // 对列表中的每个 Shape 调用,都会执行其对应子类的 CalculateArea } } }
在这个例子中,PrintShapeArea
方法接受一个 Shape
类型的参数。当你传入 Circle
对象或 Rectangle
对象时,该方法内部调用 shape.CalculateArea()
会自动调用到 Circle
或 Rectangle
类中重写的 CalculateArea
方法,这就是多态。它使得 PrintShapeArea
方法能够处理各种不同类型的图形,而无需知道它们的具体类型。
多线程之间的交互方式有几种,如何交互,各自的优缺点是什么
C# 中多线程交互主要围绕共享数据的访问控制和线程间的信令。常见方式包括:
共享内存/变量 + 锁 (Locking)
- 如何交互: 多个线程访问同一个对象或变量。使用
lock
语句 (基于Monitor
)、Mutex
、Semaphore(Slim)
、ReaderWriterLockSlim
等同步原语来保护共享资源,确保同一时间只有一个(或有限个)线程访问临界区代码。使用volatile
关键字或Interlocked
类进行原子操作。 - 优点:
- 直接:对于简单的共享状态很直观。
- 灵活性高:可以构建复杂的同步逻辑。
- 缺点:
- 容易出错:容易产生死锁 (Deadlock)、活锁 (Livelock)、饿死 (Starvation)、竞争条件 (Race Condition)。
- 性能开销:锁竞争激烈时,会导致线程阻塞和上下文切换,降低性能。
- 复杂性:难以编写、调试和维护正确的并发代码。
- 如何交互: 多个线程访问同一个对象或变量。使用
信号构造 (Signaling Constructs)
- 如何交互: 使用
ManualResetEvent(Slim)
、AutoResetEvent
、CountdownEvent
、Barrier
等类。一个线程可以通过调用Set()
来发出信号,另一个或多个线程可以通过调用WaitOne()
或Wait()
来等待信号。用于协调线程的执行顺序或等待某个条件满足。 - 优点:
- 意图清晰:明确表达了等待/通知的逻辑。
- 解耦:比直接轮询共享变量更好。
- 缺点:
- 可能导致死锁:如果信号逻辑设计不当(如互相等待)。
- 复杂性:管理多个信号和等待条件可能变得复杂。
AutoResetEvent
只能唤醒一个等待线程,可能不适用于广播场景。
- 如何交互: 使用
阻塞集合 / 生产者-消费者模式 (Blocking Collections / Producer-Consumer)
- 如何交互: 使用线程安全的集合,如
BlockingCollection<T>
(推荐) 或ConcurrentQueue<T>
,ConcurrentStack<T>
,ConcurrentBag<T>
,ConcurrentDictionary<T, V>
。生产者线程向集合中添加数据项,消费者线程从集合中移除/处理数据项。BlockingCollection
会在集合为空时阻塞消费者,或在集合满(如果设置了容量)时阻塞生产者。 - 优点:
- 简化同步:集合本身处理了大部分同步细节。
- 高度解耦:生产者和消费者通常不需要直接了解对方。
- 缓冲和流量控制:可以有效地平衡生产和消费速率。
- 缺点:
- 适用场景:主要适用于生产者-消费者这类数据流模式。
BlockingCollection
的完成机制 (CompleteAdding
) 需要正确管理。
- 如何交互: 使用线程安全的集合,如
任务并行库 (TPL) 和 Async/Await
- 如何交互: 使用
Task
,Task<TResult>
,async
/await
。可以通过Task.Wait()
,Task.Result
,Task.WhenAll()
,Task.WhenAny()
等待任务完成。使用TaskCompletionSource<T>
创建可以手动控制完成状态的任务,用于桥接回调或事件。使用async
/await
可以非阻塞地等待异步操作完成,释放线程执行其他任务。CancellationToken
用于协作式取消。 - 优点:
- 高级抽象:简化了异步和并行编程。
- 与 UI 线程友好:
await
通常能自动返回原始上下文(如 UI 线程)。 - 组合性好:容易组合多个异步操作。
- 内置取消支持。
- 缺点:
- 学习曲线:需要理解
async
/await
的工作原理和状态机。 - 不直接用于底层的线程间精细同步控制(但可以结合其他机制)。
- 主要面向异步 I/O 或计算密集型任务的并行化,而非通用的线程间消息传递。
- 学习曲线:需要理解
- 如何交互: 使用
选择哪种方式取决于具体的交互需求、性能要求和复杂性权衡。 现代 C# 开发中,推荐优先考虑 TPL 和 Async/Await,以及阻塞集合,因为它们提供了更高级、更安全的抽象。只有在必要时才使用底层的锁和信号构造。
文件读写是怎么完成的?
在 C# 中,文件读写主要通过 System.IO
命名空间下的类来完成。核心概念是 流 (Stream)。
基本步骤和常用类:
获取文件流 (FileStream):
- 使用
FileStream
类来打开或创建一个文件,并获得一个表示该文件内容的流对象。 - 构造函数需要指定文件路径、文件模式 (
FileMode
:Create
,Open
,Append
等)、文件访问权限 (FileAccess
:Read
,Write
,ReadWrite
) 和共享权限 (FileShare
)。 - 关键:
FileStream
需要被正确释放(关闭文件句柄),通常使用using
语句来确保。
csharpstring filePath = "myFile.txt"; using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { // 在这里对 fs 进行读写操作 } // using 结束时,fs.Dispose() 会被自动调用,关闭文件
- 使用
使用读取器/写入器 (Reader/Writer):
- 直接操作
FileStream
(字节流) 比较底层。通常我们会使用更方便的读取器 (Reader) 和写入器 (Writer) 类来处理特定格式的数据(如文本或二进制)。 - 文本文件:
StreamReader
: 用于从流中读取文本。可以指定编码 (Encoding
)。常用方法:ReadToEnd()
,ReadLine()
,Read()
.StreamWriter
: 用于向流中写入文本。可以指定编码。常用方法:Write()
,WriteLine()
.- 关键:Reader/Writer 通常也应放在
using
语句中,或者确保其Dispose()
被调用(它会负责关闭底层的流)。
csharp// 写文本文件 using (StreamWriter writer = new StreamWriter(filePath, append: false, encoding: System.Text.Encoding.UTF8)) { writer.WriteLine("Hello, World!"); writer.Write("This is line two."); } // writer.Dispose() 会自动调用,也会关闭 FileStream (如果是由 StreamWriter 创建的话) // 读文本文件 using (StreamReader reader = new StreamReader(filePath, System.Text.Encoding.UTF8)) { string line; while ((line = reader.ReadLine()) != null) { Console.WriteLine(line); } // 或者 string allText = reader.ReadToEnd(); }
- 二进制文件:
BinaryReader
: 用于从流中读取二进制基元数据类型(如int
,double
,byte[]
)。BinaryWriter
: 用于向流中写入二进制基元数据类型。
csharpusing (FileStream fs = new FileStream("data.bin", FileMode.Create)) using (BinaryWriter writer = new BinaryWriter(fs)) { writer.Write(123); // 写入 int writer.Write(3.14159); // 写入 double writer.Write("Test"); // 写入 string (带长度前缀) } using (FileStream fs = new FileStream("data.bin", FileMode.Open)) using (BinaryReader reader = new BinaryReader(fs)) { int i = reader.ReadInt32(); double d = reader.ReadDouble(); string s = reader.ReadString(); Console.WriteLine($"Read: {i}, {d}, {s}"); }
- 直接操作
使用静态辅助类 (File and FileInfo):
System.IO.File
类提供了静态方法,用于简化常见的文件操作(如一次性读写整个文件),内部封装了流的操作和资源管理。System.IO.FileInfo
类提供了实例方法,用于获取文件的属性和进行操作。- 常用静态方法:
File.ReadAllText(path)
/File.WriteAllText(path, content)
File.ReadAllLines(path)
/File.WriteAllLines(path, lines)
File.ReadAllBytes(path)
/File.WriteAllBytes(path, bytes)
File.Exists(path)
,File.Copy(source, dest)
,File.Move(source, dest)
,File.Delete(path)
- 这些静态方法适用于读写较小文件,因为它们会将整个文件内容加载到内存中。对于大文件,还是应该使用流式处理。
csharp// 简化读写 string content = File.ReadAllText(filePath); Console.WriteLine("Content read using File.ReadAllText:\n" + content); string[] lines = { "First line", "Second line" }; File.WriteAllLines("newfile.txt", lines);
异步文件操作:
- 为了避免阻塞线程(尤其是 UI 线程或 ASP.NET 请求线程),对于可能耗时的文件 I/O,应使用异步方法。
FileStream
,StreamReader
,StreamWriter
等都提供了对应的异步版本,如ReadAsync()
,WriteAsync()
,ReadLineAsync()
,ReadToEndAsync()
,CopyToAsync()
。- 这些方法返回
Task
或Task<TResult>
,应与async
/await
关键字配合使用。
csharppublic async Task ProcessFileAsync(string filePath) { using (StreamReader reader = new StreamReader(filePath)) { string content = await reader.ReadToEndAsync(); // 处理 content... Console.WriteLine("File read asynchronously."); } }
总结:文件读写通过 System.IO
中的流 (Stream) 来完成,通常配合 Reader/Writer 或静态 File 类进行。核心要点是使用 using
语句确保资源释放,并根据文件大小和应用场景(同步/异步)选择合适的方法。
C#的面向对象的特征
C# 是一种完全面向对象的编程语言,其主要面向对象特征包括:
- 封装 (Encapsulation):
- 将数据(字段)和操作数据的方法(方法、属性)捆绑到一个单元(类或结构)中。
- 通过访问修饰符(
public
,private
,protected
,internal
等)控制对成员的访问权限,隐藏内部实现细节,只暴露必要的接口。 - 优点:提高代码的安全性、模块性和可维护性。
- 继承 (Inheritance):
- 允许一个类(子类/派生类)继承另一个类(父类/基类)的属性和方法(非
private
成员)。 - 实现了代码重用,并建立了类之间的 "is-a" (是一个) 关系。
- C# 支持单类继承和多接口实现。
- 优点:代码复用,易于扩展和维护层次结构。
- 允许一个类(子类/派生类)继承另一个类(父类/基类)的属性和方法(非
- 多态 (Polymorphism):
- 允许不同类的对象对相同的方法调用做出不同的响应。即“同一接口,多种实现”。
- 主要通过方法重写 (override)(基于
virtual
或abstract
方法)和接口实现来实现。 - 使得可以使用基类或接口类型的引用来统一处理不同子类或实现类的对象。
- 优点:提高代码的灵活性和可扩展性,降低耦合度。
- 抽象 (Abstraction):
- 隐藏对象的复杂实现细节,只向用户暴露必要的功能接口。
- 可以通过抽象类 (abstract class) 和接口 (interface) 来实现。
- 抽象类可以提供部分实现和抽象成员(必须被子类实现),接口则完全定义契约(所有成员都必须被实现类实现)。
- 优点:简化复杂系统,降低耦合,提高可理解性。
这四个特征共同构成了 C# 面向对象编程的基础,使得开发者能够构建出模块化、可扩展、可维护和易于理解的应用程序。
C#可不可以多继承,如何多继承?
类的多继承:不可以。C# 不支持一个类直接从多个基类继承。这主要是为了避免多重继承可能带来的“菱形继承问题” (Diamond Problem),即如果一个类继承的两个父类都继承自同一个更远的基类,并且这两个父类都重写了那个基类的某个方法,那么子类应该继承哪个实现?这会产生歧义和复杂性。
如何实现类似多继承的效果?
- 接口的多重实现 (Multiple Interface Implementation):这是 C# 中推荐的方式。一个类或结构可以实现任意多个接口。接口只定义契约(方法签名、属性、事件),不包含实现(C# 8.0+ 允许接口有默认实现,但仍不能包含实例状态),因此不会有菱形继承的实现冲突问题。通过实现多个接口,一个类可以获得多种“角色”或“能力”。csharp
interface IWorker { void Work(); } interface IManager { void Manage(); } // Person 类实现了 IWorker 和 IManager 两个接口 public class Person : IWorker, IManager { public void Work() { Console.WriteLine("Working..."); } public void Manage() { Console.WriteLine("Managing..."); } }
- 组合 (Composition):一个类可以包含其他类的实例作为其成员,并通过这些成员委托调用来实现所需的功能。这是一种 "has-a" (有一个) 的关系,比继承更灵活,耦合度更低。csharp
public class Engine { public void Start() { Console.WriteLine("Engine started."); } } public class Wheels { public void Rotate() { Console.WriteLine("Wheels rotating."); } } public class Car { private Engine _engine = new Engine(); // 包含 Engine 实例 private Wheels _wheels = new Wheels(); // 包含 Wheels 实例 public void Drive() { _engine.Start(); // 委托给 Engine _wheels.Rotate(); // 委托给 Wheels Console.WriteLine("Car is driving."); } }
- 使用 C# 8.0+ 接口的默认实现:接口可以提供方法的默认实现。如果一个类实现了带有默认实现的接口,它可以直接使用该默认实现,或者提供自己的实现来覆盖它。这在一定程度上模拟了“混入 (Mixin)” 的概念,但仍需谨慎使用,且不能包含实例状态。
- 接口的多重实现 (Multiple Interface Implementation):这是 C# 中推荐的方式。一个类或结构可以实现任意多个接口。接口只定义契约(方法签名、属性、事件),不包含实现(C# 8.0+ 允许接口有默认实现,但仍不能包含实例状态),因此不会有菱形继承的实现冲突问题。通过实现多个接口,一个类可以获得多种“角色”或“能力”。
总结:C# 不允许类的多重继承,但可以通过实现多个接口或使用组合来达到相似的设计目标,这些方式通常被认为是更优、更灵活的设计选择。
回调模式
回调模式指的是通过将一个方法作为参数传递给另一个方法,从而允许被调用的方法在适当的时机回调(执行)传递的方法,这种模式通常用于异步编程或事件驱动的场景中
- 委托回调
- Lambda 表达式或匿名方法作为回调
- 事件回调
as和()强转的区别
在 C# 中,as
和强制类型转换 ((Type)
) 都用于将一个对象转换为另一个类型,但它们的行为和使用场景有所不同。
as
关键字
- 用途:用于将一个对象转换为指定类型,如果转换失败,则返回
null
。 - 语法:
object obj = someObject as TargetType;
- 特点:
- 如果
someObject
不能转换为TargetType
,则obj
将被赋值为null
。 - 不会抛出异常,因此在转换失败时可以安全地检查结果是否为
null
。 - 适用于可能不确定类型的情况,避免了异常处理的开销。
- 如果
- 示例:csharp
object someObject = "Hello, World!"; string str = someObject as string; // 成功转换,str 为 "Hello, World!" object anotherObject = 123; string anotherStr = anotherObject as string; // 转换失败,anotherStr 为 null
强制类型转换 ((Type)
)
- 用途:用于将一个对象强制转换为指定类型,如果转换失败,则抛出
InvalidCastException
异常。 - 语法:
TargetType obj = (TargetType)someObject;
- 特点:
- 如果
someObject
不能转换为TargetType
,将抛出异常,导致程序中断。 - 适用于你确信对象可以转换为目标类型的情况。
- 可以在转换失败时捕获异常进行处理,但这通常会增加代码复杂性和性能开销。
- 如果
- 示例:csharp
object someObject = "Hello, World!"; string str = (string)someObject; // 成功转换,str 为 "Hello, World!" object anotherObject = 123; try { string anotherStr = (string)anotherObject; // 转换失败,抛出 InvalidCastException } catch (InvalidCastException ex) { Console.WriteLine("Conversion failed: " + ex.Message); }
类与接口的关系
实现关系:接口定义了方法或属性的声明,但是不提供具体实现,没有方法体。类实现接口时,必须提供所有接口成员的具体实现。
硬件选型
视觉系统的组成
主机、相机、镜头、光学支架、光源、数据线、电源线
视觉常用距离
- 工作距离:被测物体表面与镜头镜片的距离。
- 物距:物体到镜头光学中心的距离。
- 像距:镜头光学中心到成像平面的距离。
- 焦距:镜头光学中心到焦点的距离。
- 最小工作距离:镜头能够保持清晰成像的最短距离。
- 视场:相机拍摄区域的大小。
常用硬件及厂商
- 相机:海康威视、cognex(康耐视)、basler(巴斯勒)、基恩士、索尼、大华、FLIR(普析通用)、IDS、JAI、OPT
- 镜头:海康、OPT、佳能、尼康、富士、Computar
- 远心镜头:视清、灿锐
- 光源:海康、OPT、嘉励、纬朗、松下、沃德普、东冠科技
- PLC:西门子、三菱、欧姆龙、施耐德、基恩士
- 机械手:发那科(FANUC)、ABB、安川、库卡(KUKA)、那智(NACHI)、爱普生、雅马哈。四轴机械手精度:0.02mm以内
- 扫码枪:基恩士(KEYENCE)、Cognex、德力捷(如果被问到具体类型可以查下)
- 3D激光:基恩士(KEYENCE)、Cognex、LMI、SmartRay
- 智能相机:智能相机(Smart Camera)并不是一台简单的相机,而是一种高度集成化的微小型机器视觉系统。它将图像的采集、处理与通信功能集成于单一相机内,从而提供了具有多功能、模块化、高可靠性、易于实现的机器视觉解决方案。品牌有 Cognex、基恩士
国内比较大的视觉和软件公司
- 海康(现改为 海康机器人):相机、镜头、视觉软件(VisionMaster)(包含了传统和深度学习算法)
- 大华(现在改为 华睿科技):相机等硬件和视觉软件
- 大恒:软件
- 凌云光:视觉软件
- 阿丘:深度学习软件aidi
国际比较大牌的视觉软硬件公司
基恩士(KEYENCE):视觉软件、3D激光、PLC、扫码枪、智能相机 工厂用的标准测量设备一般都选基恩士 康耐视(Cognex):视觉软件 VisionPro、扫码枪、相机、智能相机(智能相机软件Insight)、也提供完整的视觉系统、Cognex提供类似VisiualStudio的软件 叫Designer、深度学习软件VIDI Mvtec公司:halcon视觉软件 Labview软件:美国NI公司的 可以做视觉检测、运动控制(和PLC类似)、硬件测试 OpenCV 开源的视觉算法库
运动控制卡品牌
和PLC一样的功能,用C#编写运动控制的软件,固高、凌华、雷赛、
调整图像亮度的方法
- 调整光源亮度:通过调节光源的功率或使用可调光源来改变照明强度。
- 调整相机曝光:通过改变相机的曝光时间或增益来调整图像亮度。
- 调整相机增益:增加或减少相机的增益设置,以提高或降低图像亮度。
- 调整光圈大小:光圈大小影响进入相机的光线量,增大光圈可以增加亮度,减小光圈可以减少亮度。
- 使用图像处理算法:在软件中应用图像增强技术,如直方图均衡化、伽马校正等,来调整图像的亮度和对比度。
镜头
镜头分类
按功能分类:定焦镜头、变焦(倍)镜头、定光圈镜头; 按用途分类:远心镜头、FA镜头、线扫镜头、微距镜头(或者显微镜头); 按视角分类:普通镜头、广角镜头、远摄镜头; 按焦距分类:短焦距镜头、中焦距镜头、长焦距镜头。
镜头应用场景
- 定焦镜头:适用于对视野范围、精度要求较高的应用场景,如工业检测、测量等。
- 变焦镜头:适用于需要灵活调整视野范围的场景,如监控、安防等。
- 微距镜头:适用于对微小物体进行高精度拍摄的场景,如电子元件检测、印刷电路板检查等。
- 远心镜头:适用于对物体尺寸和位置要求较高的测量和检测场景,如半导体、光学元件等。
- FA镜头:适用于对光线强度和色彩要求较高的场景,如印刷、包装等。
- 线扫镜头:适用于对长条形物体进行连续拍摄的场景,如纺织品、纸张等。
- 大靶面镜头:配合大尺寸相机(高分辨率)使用,适用于对大面积物体进行拍摄的场景,如平板显示器、玻璃等。
镜头选型
首先确定应用需求(视野、精度、安装高度等)。
根据应用需求计算关键的光学性能参数。例如,由视野范围、相机芯片尺寸以及工作距离,计算焦距:视场(水平方向)/芯片(水平方向)≈工作距离/焦距
分辨率匹配:在实际应用中,应注意镜头的分辨率不低于相机的分辨率。
景深要求:对景深有要求的项目,尽可能使用小光圈;由于景深影响因素较多以及判定标准较为主观,具体的景深计算需要结合实际使用条件。
注意与光源的配合,选配合适的镜头。
注意考虑使用环境的可安装空间。
案例:
使用需求:视野为180mm×135mm,相机芯片为1″(芯片尺寸12.8mm×9.6mm),像元尺寸为3.5μm,相机接口为C型接口,工作距离小于800mm。 (1)根据焦距公式计算,可得:f′=工作距离÷(水平视场÷芯片)=800÷(180÷12.8)=56.89mm。 (2)选择最接近的焦距,f′取50mm,根据确定的焦距,计算新的工作距离,可得:新的工作距离≈(水平视场÷芯片)×焦距=(180÷12.8)×50=703.125mm,新的工作距离<800mm,因此所选定的焦距可行。 (3)像素匹配:像素=12.8÷(3.5×10-3)×9.6÷(3.5×10-3)=1.00×107 ,建议选择高清晰1000万像素级定焦镜头。 (4)确定接口为C接口。 (5)综上所述,可选择OPT Machine Vision的OPT-C5024-10M。
远心镜头的计算方式
- 光学放大倍数 = cdd靶面型号尺寸(V或者H)/视场尺寸(V或者H)
- 系统放大倍率 = 芯片短边/视野短边 = 7.452mm/25mm = 0.29808
一些选型的公式
- 焦距 f =WD * 靶面尺寸(H or V) / FOV(H or V)
- 焦距越小,景深越大,畸变越大,见晕现象越严重,使像差边缘的照度降低
- 视场FOV(H or V) = WD * 靶面尺寸(H or V) / 焦距f
- 视场FOV(H or V) = 靶面尺寸(H or V) / 光学倍率
- 工作距离WD = f(焦距) / (靶面尺寸/FOV(H or V))
- (焦距/靶面尺寸*视场大小) = 工作距离
- 光学倍率 = 靶面尺寸(H or V) /FOV(H or V)
- 分辨率 = 视野(Field of View) / 像素(Pixel)
- 像素精度 = 分辨率
靶面尺寸
机器视觉中1英寸 = 16毫米 传感器通常采用 4:3 的长宽比
- 1英寸 —— 靶面尺寸宽为12.8mm * 高9.6mm
- 1.1英寸 —— 靶面尺寸宽为12mm * 高12mm
- 4/3英寸 —— 靶面尺寸宽为18.5mm * 高13.5mm
- 1/4英寸 —— 靶面尺寸宽为2.4mm * 高3.2mm
- 1/3.6英寸 —— 靶面尺寸宽为4mm * 高3mm
- 1/3.2英寸 —— 靶面尺寸宽为4.54mm * 高3.42mm
- 1/3英寸 —— 靶面尺寸宽为4.8mm * 高3.6mm
- 1/2.5英寸 —— 靶面尺寸宽为5.76mm * 高4.29mm
- 1/2.3英寸 —— 靶面尺寸宽为6.16mm * 高4.62mm
- 1/2英寸 —— 靶面尺寸宽为6.4mm * 高4.8mm
- 1/1.8英寸 —— 靶面尺寸宽为7.18mm * 高5.32mm
- 1/1.7英寸 —— 靶面尺寸宽为7.6mm * 高5.7mm
- 2/3英寸 —— 靶面尺寸宽8.8mm * 高6.6mm
常用的工业镜头焦距有哪几种规格
5mm,8mm,12mm,16mm,25mm,35mm,50mm,75mm
远心镜头
常规的表面缺陷检测、有无判断等对系统精度要求不高时,可以选用普通镜头。对于精密测量的应用需求则考虑选择远心镜头,因为普通镜头成像时,由于不同工作距离造成放大倍率不一致而造成视差,即产生近大远小的效果,从而影响测量精度。远心镜头能确保检测目标在一定范围内放大倍率一致,克服视差,从而提高测量精度。下图为普通镜头与远心镜头效果对比:
远心镜头(Telecentric lens),是为纠正传统镜头视差而设计,它可以在一定的物距范围内,使得到的图像放大倍率不会变化,简单的说这种镜头拍出来的图像没有近大远小关系。
物方远心镜头
这个小孔的作用就是只让平行入射的物方光线可以达到像平面成像。从几何关系可以看出这时像就没有近大远小的关系了。物方远心镜头的原理就这么简单。之所以叫物方远心,是因为接收平行光成像,相当于物体在无穷远处。
物方远心镜头的缺点是放大倍数与像距成直接关系。实际使用时相机安装的远近会影响放大倍数。所以每个镜头系统都要单独的标定放大倍数。
像方远心镜头
这种镜头的特点是放大倍数与像距无关,相机离得远还是近都不影响放大倍数。
双远心镜头常见问答
Q:为什么双远心镜头的体积通常比较大
A:因为双远心镜头是平行光进出,所以需要多大拍摄面积,就需要多大面积的平行光进入,因此就需要多大面积的镜筒,所以双远心镜头体积通常都比较大,而且视场越大,体积越大。
Q:双远心镜头配合什么样的光源效果比较好?
A:由于远心镜头只接受平行光,滤除了几乎所有的漫反射光源,所以在自然环境下成像比较暗,所以选用平行光源能够最大限度的发挥双远心镜头的优势,使被测物体边缘清晰、稳定,并有效去除检测过程中的噪声。
相机
相机选型
- 分辨率
- 分辨率是指相机能够捕捉的图像细节的数量,通常以像素(Pixel)表示。分辨率越高,图像越清晰,但数据量也越大。
- 选择相机时,需要根据应用需求确定所需的分辨率。例如,对于精密测量或高精度检测,可能需要更高的分辨率。
- 帧率
- 帧率是指相机每秒钟能够捕捉的图像帧数,通常以 FPS(Frames Per Second)表示。帧率越高,图像更新越快,但数据量也越大。
- 选择相机时,需要根据应用需求确定所需的帧率。例如,对于高速运动物体的检测,可能需要更高的帧率。
- 曝光时间
- 曝光时间是指相机传感器接收光线的时间长度。曝光时间越长,图像越亮,但可能导致运动模糊。
- 选择相机时,需要根据应用环境的光照条件和运动速度确定合适的曝光时间。
- 曝光时间通常以毫秒(ms)或微秒(μs)表示。
- 像元尺寸
- 像元尺寸是指相机传感器上每个像素的物理尺寸,通常以微米(μm)表示。像元尺寸越大,传感器对光线的灵敏度越高,但分辨率可能较低。
- 选择相机时,需要根据应用需求和光照条件确定合适的像元尺寸。例如,在低光照环境下,可能需要较大的像元尺寸以提高图像质量。
- 动态范围
- 动态范围是指相机能够捕捉的最亮和最暗部分之间的光强差异,通常以分贝(dB)表示。动态范围越大,相机能够处理的光照变化越大。(亮的地方不过曝,暗的地方不死黑)
- 选择相机时,需要根据应用环境的光照条件和对比度要求确定合适的动态范围。
- 快门类型
- 机械快门:焦平面快门、中央快门
- 电子快门:全局快门、滚动快门(卷帘快门)
- 传感器类型
- 传感器类型会影响相机的成像性能和适用场景。常见的传感器类型包括 CCD 和 CMOS。
- CCD 传感器通常具有更高的图像质量和灵敏度,但成本较高,功耗较大。CMOS 传感器则具有更快的读出速度和更低的功耗,适合高速应用。
- 光谱范围
- 光谱范围是指相机能够捕捉的光线波长范围。不同的应用可能需要不同光谱范围的相机,例如,某些工业检测可能需要近红外或紫外光谱范围的相机。
- 接口类型
- 接口类型决定了相机与计算机或其他设备之间的连接方式。常见的接口类型包括 USB、GigE(千兆网)、Camera Link 等。
- 选择相机时,需要根据系统架构和数据传输需求确定合适的接口类型。
- 相机与镜头接口类型
- C接口、CS接口、F接口、T接口、M接口
- 触发模式
- 触发模式决定了相机何时捕捉图像。常见的触发模式包括自由运行、外部触发和软件触发等。
- 选择相机时,需要根据应用需求确定合适的触发模式。例如,对于高速运动物体的检测,可能需要外部触发模式以确保捕捉到关键帧。
- 相机尺寸和重量
- 相机的尺寸和重量会影响安装和使用的灵活性。对于空间受限的应用,可能需要选择小型轻量化的相机。
- 软件支持
- 相机通常需要配套的软件进行配置和图像处理。选择相机时,需要考虑软件的易用性、功能和兼容性。
- 一些相机厂商提供 SDK(Software Development Kit)以便于开发者集成相机功能。
- 成本
- 成本是选择相机时需要考虑的重要因素。不同型号和规格的相机价格差异较大,开发者需要根据预算和项目需求做出合理选择。
- 环境要求
- 环境要求包括相机的工作温度、湿度、抗震动能力等。选择相机时,需要确保其能够在预期的工作环境中正常运行。
曝光和增益一般有什么作用
曝光和增益是相机成像过程中两个重要的参数,它们直接影响图像的亮度、对比度和清晰度。
- 曝光(Exposure):曝光是指相机传感器接收光线的时间长度。曝光时间越长,传感器接收到的光线越多,图像就越亮。曝光时间过短可能导致图像过暗,而曝光时间过长可能导致图像过曝(过亮),细节丢失。
- 曝光时间通常以秒或毫秒为单位表示。
- 在低光照条件下,增加曝光时间可以提高图像亮度,但也可能导致运动模糊。
- 增益(Gain):增益是指对图像信号进行放大的过程。增益可以提高图像的亮度,但过高的增益会引入噪声,降低图像质量。增益通常以分贝(dB)表示。
- 增益可以在软件中调整,也可以通过相机的硬件设置进行调整。
- 增益的作用是提高图像的信噪比,使得在低光照条件下仍能获得较清晰的图像。
- 增益过高会导致图像噪声增加,影响图像质量,因此需要根据实际情况进行合理调整。
曝光和增益是直接控制传感器(CDD/CMOS)上读出的数据,是要优先调节的,以调节曝光时间为主,在不过爆的前提下,增加曝光时间可以增加信噪比,使图像更加清晰,当然对于很弱的信号,曝光也不能无限增加,因为随着曝光时间的增加噪音也会累积,曝光补偿就是增加曝光拍摄时的曝光量。
增益一般只是在信号弱,但不想增加曝光时间的情况下使用,一般相机增益都产生很大的噪音,工业相机在不同增益时图像的成像质量不一样,增益越小,噪点越少,增益越大,噪点越多,特别是在暗处,数码相机的ISO就是这里说的增益,增大ISO,是增加感光器件对光的灵敏度。高感光度对低光照灵敏,同时也对噪杂信号也灵敏,信噪比小,所以高感光度噪点也多(可以利用图片软件的降噪功能减轻或去除)。
调节亮度增益说白了就是改变ISO,改变CMOS传感器的感光性能,但是会影响到画质,调节曝光简单来将就是按下快门的时间,时间越长,图片越亮。
什么是物距
物距(Object Distance)是指物体到相机镜头的距离。在机器视觉中,物距是一个重要的参数,因为它直接影响到成像质量、视场大小和焦距等因素。
- 物距越近,成像的细节越清晰,但视场范围可能会变小。
- 物距越远,成像的细节可能会变模糊,但视场范围可能会变大。
- 在选择镜头时,需要根据物距来计算焦距和视场大小,以确保能够满足应用需求。
描述一下景深
- 图像中可以被清晰聚焦的前景和背景之间的距离
- 景深是在聚焦完成后,焦点前后的范围所呈现的清晰图像的距离,这一前一后的范围叫做景深
- 镜头焦距越小,景深越大
- 物距越大,景深越大
- 光圈越小,景深越大
如何增大景深
小光圈,小焦距,大工作距离,大光源亮度
相机接口
F型、C型、CS型、M58型、M72型、F型
- F接口一般适用于焦距大于25mm的镜头
- C与CS接口的区别在于镜头与摄像机接触面至镜头焦平面的距离不同,C型接口此距离为17.5mm,CS型接口此距离为12.5mm,C接口镜头使用5mm的c/cs转接环可以安装在CS型接口的摄像机上,反之则不行。
视场(Field of View 即 FOV)
指观测物体的可视范围,也就是充满相机采集芯片的物体部分
工作距离(Working Distance 即WD)
指镜头前部到受检验物体的距离,即清晰成像的表面距离
失真(distortion)
又称畸变,指被摄物平面内的主轴外直线,经光学系统成像后变为曲线,则此光学系统的成像误差称为畸变
相机的选型
分辨率
先看物体的尺寸->精度要求->预留视野->确认分辨率大小 计算公式:(视野尺寸/像素尺寸) * 0.75 = 分辨率
运动状态
运动状态:速度快,线扫相机、全局快门;静态低速就用面阵相机、卷帘快门。
传感器类型
- CCD:高质量图像,低噪声,适合静态图像捕捉,但成本较高。
- CMOS:成本低,功耗小,适合高速图像捕捉,但可能存在噪声问题。
相机类型
- 面阵相机:适合静态图像捕捉,分辨率高,适用于大多数应用场景。
- 线阵相机:适合高速运动物体的捕捉,通常用于工业检测和扫描应用。
快门类型
应用场景对比
应用类型 | 推荐快门类型 | 典型应用 |
---|---|---|
静态/慢速检测 | 卷帘快门 | 机器人拾放、PCB检查、显微镜检查 |
高速运动检测 | 全局快门 | 车牌识别(ANPR)、高速生产线检测、汽车工业 |
选择建议
预算有限 + 静态目标 → 选择卷帘快门 高精度 + 运动目标 → 选择全局快门 高分辨率需求 → 优先考虑卷帘快门 高速生产线 → 必须选择全局快门
卷帘快门 (Rolling Shutter)
- 工作原理 逐行捕捉像素,从上到下或左到右依次扫描构建完整图像 传感器网格中的光传感器按顺序工作
- 优点 成本低:传感器尺寸更小,制造成本更低 数据处理简单:每次只处理少量图像数据 设备紧凑:相机体积更小更轻便 高分辨率支持好:适合处理高分辨率图像
- 缺点 运动失真:第一行和最后一行像素捕获存在时间差 快速移动物体变形:高速运动对象可能出现扭曲或模糊
全局快门 (Global Shutter)
- 工作原理 同时曝光所有像素,在同一时刻捕获整个图像 所有传感器同步工作
- 优点 无运动失真:避免快速移动物体的图像变形 高速成像:适合高速运动场景 图像质量稳定:运动物体成像清晰
- 缺点 成本高:传感器更大更复杂,价格昂贵 帧率限制:高分辨率时最大帧率可能较低 设备体积大:传感器尺寸更大
色彩
是不是对拍摄的颜色有要求,如果要是需要颜色信息就彩色,不需要就黑白,一般都是黑白
CCD的工作原理是什么
光到达CCD某个像素时,根据光的强度产生相应的电荷,将该电荷的大小读取为电信号,即可获得各个像素上光的强度(灰度值)
像素是什么
像素是指数字图像的最小单位,是一个可以检测光强度的传感器(光电二极管)
分辨率是什么
像素的密度,像素越多,图像的密度越大,对细节的表现就越强
精度是什么
精度 = 分辨率 * 有效像素
分辨率 (Resolution)
- 指每个像素在现实世界中代表的物理尺寸
- 单位:mm/pixel 或 μm/pixel
- 计算方式:视野尺寸 ÷ 图像像素数
有效像素 (Effective Pixels)
- 指能够稳定区分目标特征所需的最少像素数量
- 通常取决于光照条件(正面光:1个像素,背光:0.5个像素)
- 图像质量
- 检测算法要求
举例说明
- 视野:10mm
- 相机分辨率:1000×1000像素
- 分辨率 = 10mm ÷ 1000pixel = 0.01mm/pixel
不同光照条件下的精度:
- 正面光照:精度 = 0.01mm/pixel × 1pixel = 0.01mm
- 背光照明:精度 = 0.01mm/pixel × 0.5pixel = 0.005mm
物理意义
这个精度值表示系统能够可靠检测到的最小缺陷尺寸或最小测量单位。
实际应用考虑
- 光照影响:背光因为边缘更清晰,所以有效像素可以取0.5
- 检测内容:测量类应用通常需要更高精度
- 系统稳定性:实际应用中还要考虑机械振动、温度变化等因素
精度的单位是mm,根据产品表面和照明状况的不同,我们可以通过放大图像观察辨别稳定像素的个数,从而得出精度,如果条件不允许实际测试观察,一般的规律是:如果使用正面打光,有效像素为1个,使用背光,有效像素为0.5个
光圈是什么
光圈是控制光线透过镜头,进入机身内感光面的光量的装置
光源
选择合适的光源,可突显良好的图像效果(特征点),可以简化算法、提高检测精度、保证检测系统的稳定性。 光源的选择需要考虑以下几个方面:
- 任务需求:检测(识别)、测量、定位、条形码、字符识别、三维扫描等。
- 性能要求:检测内容、检测速度、检测精度等。
- 其他配合:如相机、镜头、软件、安装方式等。
光源颜色的种类
白色光源(W)
白色光源通常用色温来界定,色温高的颜色偏蓝色(冷色,色温>5000K),色温低的颜色偏红(暖色,色温<3300K),界于3300与5000K之间称之为中间色,白色光源适用性广,亮度高,特别是拍摄彩色图像时使用更多。
蓝色光源(B)
蓝色光源波光为430-480之间,适用产品:银色背景产品(如钣金,车加工件等)、薄膜上金属印刷品。
红色光源(R)
红色光源的波长通常在600-720之间,其波长比较长,可以透过一些比较暗的物体,例如底材黑色的透明软板孔位定位、绿色线路板线路检测,透光膜厚度检测等,采用红色光源更能提高对比度。
绿色光源(G)
绿色光源波长510-530,界于红色与蓝色之间,主要针对产品:红色背景产品,银色背景产品(如钣金,车加工件等)。
红外光(IR)
红外光的波长一般为780-1400,我司大多采用940波长的红外光,红外光属于不可见光,其透过力强。一般LCD屏检测、视频监控行业应用比较普遍。
紫外光(UV)
紫外光的波长一般为190-400,我司主要采用385波长的紫外光,其波长短,穿透力强,主要应用于证件检测、触摸屏ITO检测、布料表面破损、点胶溢胶检测等方面,金属表面划痕检测等缺陷检测。
互补色
互补色是指在色轮上相对的颜色,它们可以相互抵消,形成灰色或白色。互补色的使用可以增强图像的对比度和清晰度。
红色的背景,白色的字体,该选用什么光源
绿色光源,如果要将目标打成白色需要选用同类色,如果要目标打成黑色,需要选用互补色。
- 如果想变暗的特征是红色则使用绿光
- 使用绿光能使绿色特征呈现的更亮
光源的种类
- 环形光源:分为高、中、低角度,适合检测物体表面的特征,如字符,喷码检测,平衡阴影和表面细节的检测。
- 条形光源:尺寸灵活,可以拼接成四面光源,适合从物体侧面打光。
- 背光源:从物品底部打光,凸显物品边缘信息,适合透明物体的污渍检测。
- 点光源:聚光效果强,适合视场比较小的场景运用
- 穹顶光源:可使光线在整个直径范围内均匀分布,适用于高低不平表面或反光材质检测。
- 同轴光源:使光能够与镜头同轴,抑制重影,提高清晰度,适合反光材质的被测物体。
- LED光源:节能、环保、使用寿命长。
- AOI光源:多角度的彩色照明,凸显待测物表面的高低水平细节,适用于PCB元件的遗漏/错误/歪斜的缺陷检查、锡膏量多/量少/有无的状态检查以及其他PCB元件与焊点缺陷检查
打光方式
角度照射
在一定工作距离下,光束集中、亮度高、均匀性好、照射面积相对较小。常用于液晶校正、塑胶容器检查、工件螺孔定位、标签检查、管脚检查、集成电路印字检查等(30、45、60、75等角度环光)。
垂直照射
照射面积大、光照均匀性好、适用于较大面积照明。可用于基底和线路板定位、晶片部件检查等(0角度环光、面光源)。
低角度照射
对表面凹凸表现力强。适用于晶片或玻璃基片上的伤痕检查(90度环光)。
背光照射
发光面是一个漫射面,均匀性好。可用于镜面反射材料,如晶片或玻璃基底上的伤痕检测;LCD检测;微小电子元件尺寸、形状,靶标测试。(背光源、平行背光源)
多角度照射
RGB三种不同颜色不同角度光照,可以实现焊点的三维信息的提取。适用于组装机板的焊锡部份、球形或半圆形物体、其他奇怪形状物体、接脚头(AOI光源)
碗状光照明
360度底部发光,通过碗状内壁发射,形成球形均匀光照。用于检测曲面的金属表面文字和缺陷。(球积分光源,通常也叫圆顶光)
同轴光照明
类似于平行光的应用,光源前面带漫反射板,形成二次光源,光线主要趋于平行。用于半导体、PCB板、以及金属零件的表面成像检测,微小元件的外形、尺寸测量。(同轴光源,平行同轴光源)
辅助光学器件
- 反射镜:反射镜可以简单方便的改变优化光源的光路和角度,从而为光源的安装提供 了更大的选择空间。
- 分光镜:分光镜通过特殊的镀膜技术,不同的镀膜参数可以实现反射光和折射光比例 的任意调节。机器视觉光源中的同轴光就是分光镜的具体应用。
- 棱镜:不同频率的光在介质中的折射率是不同的,根据光学的这一基本原理可以把不同颜色的复合光分开,从而得到频率较为单一的光源。
- 偏振片(偏光板):光线在非金属表面的反射是偏振光,借助于偏振片可以有效的消除物体的表面反光。同时,偏振片在透明或半透明物体的应力检测上也有很好的应用。
- 漫射片(扩散板):漫射片是机器视觉光源中比较常见的一种光学器件,它可以使光照变得更均匀,减少不需要的反光。
- 光纤:光纤可以将光束聚集于光纤管中,使之想水流一样便于光线的传输,为光源的安装提供了很大的灵活性。
光源选型的过程
- 提出问题
- 定义检测目标
- 收集制定完整的规格列表
- 可行性研究:a 这个零件是如何被肉眼看到的;b 这个零件将如何照射其上的光学特性;c 将自己想成这个零件
- 概念设计
- 实验室的反复试验
- 原型产品生产
- 试用、反馈、改进
- 批量生产、制造。
光源选择的注意事项
- 镜头的工作距离;
- 现场的安装障碍;
- 照明对象的现场实际情况;
- 照明对象特征是否存在特殊性;
- 图像是否需要彩色;
- 安装的便利性;
- 成本;
条光选型要领
- 条光照射宽度最好大于检测的距离,否则可能会照射距离远造成亮度差,或者是距离近而幅射面积不够;
- 条光长度能够照明所需打亮的位置即可,无须太长造成安装不便,同时也增加成本,一般情况下,光源的安装高度会影响到所选用条光的长度,高度越高,光源长度要求越长,否则图像两侧亮度传经比中间暗;
- 如果照明目标是高反光物体,最好加上漫射板,如果是黑色等暗色不反光产品,也可以拆掉漫射板以提高亮度;
环光选型要领
- 了解光源安装距离,过滤掉某些角度光源;例如要求光源安装尺寸高,就可以过滤掉大角度光源,选择用小角度光源,同样,安装高度越高,要求光源的直径越大;
- 目标面积小,且主要特性在表面中间,可选择小尺寸0角度或小角度光源;
- 目标需要表现的特征如果在边缘,可选择90度角环光,或大尺寸高角度环形光;
- 检测表面划伤,可选择90度角环光,尽量选择波长短的光源;
条形组合光选型要领
- 条形组合光在选择时,不一定要按照资料上的型号来选型,因为被测的目标形状、大小各不一样,所以可以按照目标尺寸来选择不同的条形光源进行组合;
- 组合光在选择时,一定要考虑光源的安装高度,再根据四边被测特征点的长度宽度选择相对应的条形光进行组合;
背光源/平行背光源造型要领
- 选择背光源时,根据物体的大小选择合适大小的背光源,以免增加成本造成浪费;
- 背光源四周一条由于的外壳遮挡,因此其亮度会低于中间部位,因此,选择背光源时,尽量不要使目标正好位于背光源边缘;
- 背光源一般在检测轮廓时,可以尽量使用波长短的光源,波长短的光源其衍射性弱,图像边缘不容易产生重影,对比度更高;
- 背光源与目标之间的距离可以通过调整来达到最佳的效果,并非离得越近效果越好,也非越远越好;
- 检测液位可以将背光源侧立使用;
- 圆轴类的产品,螺旋状的产品尽量使用平行背光源;
同轴光造型要领
- 选择同轴光时主要看其发光面积,根据目标的大小来选择合适发光面积的同轴光;
- 同轴光的发光面积最好比目标尺寸大1.5~2倍左右,因为同轴光的光路设计是让光路通过一片45度半反半透镜改变,光源靠近灯板的地方会比远离灯板的亮度高,因此,尽量选择大一点的发光面避免光线左右不均匀;
- 同轴光在安装时尽量不要离目标太高,越高,要求选用的同轴光越大,才能保证才均匀性;
平行同轴光选型要领
- 平行同轴光光路设计独特,主要适用于检测各种划痕;
- 平行同轴光与同轴光表现的特性不一样,不能替代同轴光使用;
- 平行同轴光检测划伤之类的产品,尽量不要选择波长长的光源;
其他光源选型要领
1、了解特征点面积大小,选择合适尺寸的光源; 2. 了解产品特性,选择不同类型的光源; 3. 了解产品的材质,选择不同颜色的光源; 4. 了解安装空间及其他可能会产生障碍的情况,选择合适的光源;
光源中的明暗场
明场光(Bright Field Lighting) 明场光是一种从正面照射目标物体的光照方式,通常是光源与相机镜头同轴或相对置放置。它主要用于突出物体表面的反光区域,增强明亮区域的对比度。 标签检测、物体形状检测、表面划痕检测 适用场景:标签检测、物体形状检测、表面划痕检测
暗场光(Dark Field Lighting) 暗场光是一种从侧面或较低角度照射目标物体的光照方式,光线以小角度接触物体表面,然后向外反射。这样,只有表面上的不平整部分或边缘会反射光线到相机,而平整的表面则不会反射光线,呈现出暗的效果。 适用场景:表面缺陷检测、边缘检测、微小颗粒或瑕疵检测
案例分析
护照检测
检测的内容主要有水印、微缩文字、人图象、证件的有效时间、以及其他暗号。需要多种光源(同轴光,组合条光,条光)组合使用
酒瓶盖条码检测
检测的内容主要有条码识别、条码打标位置是否偏离;使用光源:204mm、60度蓝光 选型分析:
- 了解产品特性: 瓶盖上面是黑色,另有红黑交错背景图案,条码为激光刻印显灰色,为了显现出条码,应该将字符打亮,背景与字符分辨明显;我们如果选用红色光源的话,背景中的红色会滤掉打白,会干扰同为白色的字符,所以,我们应该利用光源的互补原理,采用蓝色光源,将红色背景尽量打黑;
- 了解产品形状选择合适光源 瓶盖为圆形,直径为25MM,一般此情况可以选择同轴光或者环形光比较合适;
- 了解产品材质特性选择合适光源 瓶盖为金属材料,表面有印刷图案,比较光滑,反光度很强,选用同轴光或带角度的环形光比较合适;
- 模拟现场打光选择能用的光源 由于酒瓶必须装在包装纸箱里,瓶盖离纸箱上顶部的距离有80MM,考虑需要留一定的空间,因此,瓶盖离光源需要的距离为100MM或以上,如此高的距离,小同轴光跟小环光以及低角度光就不能满足要求,必须选用大同轴光跟大环光
- 打光试验 根据以上情况选择大致的光源后,再进行性价比对比,选择性价比高的光源进行实际打光测试(同轴光如果提到110MM距离的话,需要用到120左右的光,单位价值比较高,所以选择环形光比较经济)
- 最终确定光源 根据打光效果图进行软件处理,在得到可靠性的条件下选择正确的光源。
手机盖板ITO检测
检测手机屏ITO线路是否断路,短路,尺寸等 选型分析:
- 了解产品特性:ITO薄膜是一种n型半导体材料,具有高的导电率、高的可见光透过率,属于特殊的印刷线路,用肉眼无法看到,所以用普通的光源无法完成拍摄,这里我们选用紫外同轴光源来完成拍摄;
- 紫外光源的发光亮度比较低,这就需要光源在镜头倍率、光源安装高度、漫射板材质方面合理搭配,否则会造成上面图一的情况:亮度不够,光源灯珠影子明显,图像均匀性差;
- 选型分析:先了解拍摄视野有多少,选择好镜头后,再了解光源的安装高度,一般情况下光源会离镜头的距离比较近,然后用合适大小的紫外同轴光去打光测试,确定好最佳的工作距离,然后观察图像的均匀性,换选不同透光率的漫射板,即要保证紫外光的透过率最大化,又不能让灯珠太明显投射到图像里,亮度可以通过选择大光发尺寸的同轴光来解决;
VisionPro
用过哪些VP工具
基本上90%都用过:
- pmalign 模版匹配
- fixure 定位工具
- createGraphiclabel 创建文本
- blob 斑点工具
- 测量工具
- 查找工具
- 图像预处理工具
工具参数:
- 阈值,对比度阈值,选择区域,极性等
模板匹配里面的算法都有什么?分别有什么用?
- PatMax 涉及的点数多,精度比较高,速度稍慢,定位的精度可以为1/40像素
- PatQuick 算法速度快
- PatQuick 与PatMax算法 处于两者中间
- PatFlex算法 比较适合于畸变的情况
Visionpro中掩模和建模的区别
掩膜:遮掩不必要的像素,消除干扰,使用背景:当只需要边缘轮廓,忽略内部细节的时候使用 建模:手动创建一个需要的轮廓。通过数学或几何模型来描述或表示图像中的特定对象或形状。建模的目标是识别、定位和测量图像中的物体,甚至在噪声或部分遮挡的情况下也能实现。
模板匹配的颗粒度是什么
可以通过修改粗糙和精细的颗粒度,修改粗糙和精细特征的表现情况,颗粒度变大,选取的特征点会变少。本质上,颗粒度大,穿越的像素点就多。包围的轮廓就会变得粗糙。一般选择默认。
弹性
弹性参数:当实例和当前模板有一定的出入的时候(弹性形变),可以适当进行修改。 弹性匹配是一种灵活的模板匹配方法,能够处理图像中的变形、缩放、旋转等变化。它在需要处理复杂和变形对象的场景中具有重要意义,尽管其计算复杂度较高,但可以显著提高匹配算法的鲁棒性和适用性。
边缘阈值
低于边缘阈值的会当作物件的背景。大于阈值的才会视作物件的轮廓。(边缘对比度)如果设置一个过小的阈值,那么会产生过多的干扰,设置一个过大的阈值,将会造成边缘轮廓的损失。 边缘检测的核心是找到图像中亮度或颜色发生剧烈变化的区域,这些变化通常代表物体的边界。边缘阈值的作用是设置一个标准,只有当像素之间的亮度或颜色差异大于这个阈值时,才将其标记为边缘。
- 高阈值:如果设置的边缘阈值较高,算法会仅检测出图像中最强烈的边缘,忽略细小或弱的边缘。这适合用于噪声较多的图像中,以避免误检。
- 低阈值:如果设置的阈值较低,算法会检测出更多的边缘,包括一些较弱或细小的边缘。然而,这也可能导致噪声或微小的图像变化被误认为是边缘。
极性
极性(Polarity) 指的是物体边缘灰度变化的方向,也就是从明到暗或从暗到明的转换(从暗到亮是正极性,反之是负极性)
接受阈值
高于得分接受,低于得分抛弃
粒度限制(和创建模板是的参数基本一致)
粒度限制通常指处理过程中对细节或特征的最小尺度限制,即算法或硬件能够有效区分或处理的最小颗粒大小。较小的粒度限制意味着系统能够处理更多的细节信息,而较大的粒度限制则意味着系统只关注较大的整体特征。
对比度阈值(背景和工件的切割对比度)
对比度阈值用于设定像素之间亮度差异的最小值。如果像素之间的亮度差异(对比度)低于该阈值,则系统会忽略这些像素的变化,认为它们不构成有效的特征或边缘;如果亮度差异超过阈值,则会被认为是图像中的重要信息。
VisionPro中找线工具找圆工具的对比度阈值怎么调
对比度阈值是用来区分边缘与背景的数值。VisionPro通过图像灰度值的变化来找到边缘,对比度阈值决定了灰度值变化的敏感度。如果对比度阈值过高,可能导致遗漏某些边缘;如果过低,则可能引入噪声或干扰。 通过查看背景和边缘的像素差调试相应的大小。
C#中通过哪个方法加载VPP
ToolBlock = (CogToolBlock)CogSerializer.LoadObjectFromFile("tjjc.vpp");
二开项目中用vpp脚本连接相机流程
- 需要先连接相机,然后设置参数,看VPP平台提供的设置选项或编程接口,配置相机的各项参数,比如曝光时间,增益,帧率,分辨率什么的。
- 然后编写VPP脚本,在成功连接到相机后,编写代码以实现所需的图像处理逻辑,最后输出结果。
- 当然还得运行一下脚本,测试相机连接和图像处理功能是否正常工作。
- 还有调试问题,如果相机不能连接的话,就得用调试工具排查问题。
用自己的语言描述一下PMA,讲述一下模板匹配的输出结果?
是机器视觉中常用的算法之一,主要用于识别图像中的特定模板。它通过在图像中搜索与给定模板相匹配的区域,来定位目标物体。PMA 不依赖于图像的颜色或纹理,而是通过比较图像像素之间的相似性,找到与模板最接近的匹配。
匹配度:即匹配区域与模板的相似度,一般用百分比或相似度分数表示。匹配度越高,表示该区域与模板越相似。
匹配位置:匹配区域在图像中的具体位置,通常用坐标(如左上角点的坐标)来表示。
匹配区域大小:匹配区域的大小,可以反映目标物体在图像中的尺度。
旋转角度(如果支持旋转匹配):有些高级的模板匹配算法可以检测目标物体的旋转角度,因此输出结果还可能包含该角度信息。
专业名词
- 图像拼接(Image Stitching):将多个图像拼接成一个大图像,可以用于全景图像的生成。
- 三维重建(3D Reconstruction):将多个图像或点云数据重建成三维模型,可以用于建模和仿真。
- 相机姿态估计(Camera Pose Estimation):用于估计相机在三维空间中的位置和方向,可以用于机器人导航和定位。
- 光流(Optical Flow):用于估计图像中像素的运动,可以用于运动分析和跟踪。
- 目标检测(Object Detection):用于检测图像中的目标,可以用于自动驾驶、安防等领域。
- 分类器(Classifier):用于对图像进行分类,可以用于识别物体、人脸等。
- 神经网络(Neural Network):用于图像识别、分类、分割等任务,可以进行深度学习训练。
- 图像配准(Image Registration):用于将多个图像进行配准,可以用于医学影像、卫星遥感等领域。
- 形态学处理(Morphological Processing):用于对图像进行形态学变换,如腐蚀、膨胀等,可以用于图像分割和去噪。
- 光学字符识别(Optical Character Recognition,OCR):用于将图像中的文字转换为可编辑的文本,可以用于自动化办公、数字化档案等
visionPro工具中toolblock和toolgroup的区别
- toolblock更加灵活,可以通过右键添加输入输出,可以添加复杂和简单的脚本
- toolgroup更注重工具的组织和分类,是一个逻辑功能
vpp脚本常用来干什么
对一张图中多个物件进行识别,或者对一张图多个识别 的逻辑处理、结果展示,控制组件的运行
最后如果要显示vpp脚本的作用,需要在vpp的什么地方写什么代码?
GroupRun写逻辑代码 modifyLastRunRecord 进行结果展示 代码顶部定义变量
VisionPro工具图像预处理工具的很多功能
- 图像增强:对图像进行对比度、亮度等调整,提高图像质量。
- 图像滤波:使用不同的滤波器(如高斯滤波、中值滤波等)去除图像噪声。
- 图像变换:对图像进行几何变换,如旋转、缩放、平移等。
- 图像二值化:将图像转换为二值图像,便于后续处理。
- 图像分割:将图像分割成不同的区域,便于识别和分析。
visionPro的blob工具,高尾部和低尾部的区别
在 Cognex VisionPro 的 Blob 工具中,“高尾部”(High Tail)和“低尾部”(Low Tail)是用于优化斑点分割的参数,它们通常与灰度阈值处理相关,用于剔除斑点中过亮或过暗的像素,从而更精确地定义斑点区域。
低尾部 (Low Tail / Tail Low / Min Grey Level in Blob):
- 低尾部(Low Tail):指的是在图像中,物体的尾部区域相对较暗,通常用于检测物体的内部特征或细节。
- 作用: 从通过主阈值分割出来的潜在斑点区域中,进一步移除那些灰度值低于“低尾部”设定值的像素。
- 目的: 帮助去除斑点内部或边缘较暗的噪声、阴影或不重要区域,使得斑点更加纯净,轮廓更清晰。如果一个像素的灰度值低于这个设定值,即使它在初始阈值范围内,也不会被认为是斑点的一部分。
高尾部 (High Tail / Tail High / Max Grey Level in Blob):
- 高尾部(High Tail):指的是在图像中,物体的尾部区域相对较亮,通常用于检测物体的边缘或轮廓。
- 作用: 从通过主阈值分割出来的潜在斑点区域中,进一步移除那些灰度值高于“高尾部”设定值的像素。
- 目的: 帮助去除斑点内部或边缘过亮的噪声、高光反射或不重要区域。如果一个像素的灰度值高于这个设定值,即使它在初始阈值范围内,也不会被认为是斑点的一部分。
区别总结:
- 低尾部关注并剔除斑点中过暗的像素。
- 高尾部关注并剔除斑点中过亮的像素。
这两个参数允许用户在初始阈值分割的基础上,对斑点的灰度范围进行更精细的控制,以获得更准确的斑点分析结果(如面积、中心、轮廓等)。它们对于处理光照不均、存在反射或阴影的图像特别有用。
Halcon
提高Halcon的运行速度有哪些方法
- 使用合适的图像格式:选择合适的图像格式可以减少内存占用和处理时间。例如,使用灰度图像而不是彩色图像可以提高处理速度。
- 使用 Halcon 的内置函数:Halcon 提供了许多优化的内置函数,这些函数通常比自定义实现更快。尽量使用 Halcon 提供的函数来完成图像处理任务。
- 优化算法参数:根据具体应用场景调整算法参数,可以提高处理速度。例如,在边缘检测中,调整阈值可以减少计算量。
- 裁剪ROI区域:通过裁剪感兴趣区域(ROI),可以减少处理的图像数据量,从而提高处理速度。
- 减少图像分辨率:在处理大图像时,可以先将图像缩小到合适的分辨率,处理完成后再放大结果。这样可以减少计算量,提高速度。
- 使用多线程处理:Halcon 支持多线程处理,可以利用多核 CPU 提高处理速度。通过设置
set_system('use_threading', 'true')
可以启用多线程。 - 使用 Halcon 的并行处理功能:Halcon 提供了并行处理的功能,可以通过
parallel
关键字来实现多线程处理,从而提高处理速度。 - 使用 Halcon 的硬件加速:如果硬件支持,可以启用 GPU 加速来提高处理速度。通过设置
set_system('use_gpu', 'true')
可以启用 GPU 加速。
Halcon中数据类型有哪些
- 图像(Image):用于存储图像数据,可以是灰度图像、彩色图像等。
- 区域(Region):用于存储二值图像中的区域信息,可以表示物体的形状和位置。
- 字符串(String):用于存储文本数据,可以是单个字符或字符串。
- 数组(Array):用于存储一维或多维数据,可以是数值、字符串等类型。
- 矩阵(Matrix):用于存储二维数据,可以是数值矩阵、变换矩阵等。
- 标记(Marker):用于存储标记信息,可以表示特定的点、线或形状。
- 句柄(Handle):用于存储 Halcon 对象的引用,可以是图像、区域、模型等对象的句柄。
边缘检测算法
- Sobel:sobel_amp(Image, EdgeAmplitude, 'sum_abs', 3)
- Canny:edges_sub_pix(Image, Edges, 'canny', 1, 20, 40)
- Prewitt:prewitt(Image, EdgeImage)
- Roberts:没有直接实现,需自定义操作
- Laplace:laplace(Image, EdgeImage, 'signed', 3)
- Kirsch:通过自定义卷积实现。
halcon有几个模板比较熟悉?熟悉哪几种?
基于灰度的模版匹配 基于形状的模版匹配 基于尺度和旋转不变的形状模版匹配
halcon里的轮廓模板、相关性等模板有接触吗?
- 相关性模版匹配:
- create_ncc_model 相似度模版匹配
- find_ncc_model 发现模板
- clear_ncc_model 清除句柄 以免爆内存
Halcon中的增强算法
对比度增强(Contrast Enhancement)
scale_image 对图像灰度进行线性拉伸或压缩。
scale_image(Image, ImageScaled, 1.5, -50)
scale_image_max 自动将图像拉伸到 [0,255] 区间。
边缘增强(Edge Enhancement)
laplace 拉普拉斯算子增强图像边缘(注意图像会变得更锐利也更敏感噪声)。
highpass_image 高通滤波器,去除低频背景,保留高频细节。
highpass_image(Image, ImageHighpass, 15, 15)
sobel_amp 用 Sobel 算子增强边缘,对边缘响应更强。
sobel_amp(Image, ImageSobel, 'sum_abs', 3)
亮度增强(Brightness Adjustment)
add_image / sub_image 加亮或变暗图像像素。
add_image(Image, Image, ImageBrightened, 1, 50)
锐化(Sharpen)
- sharpen_image 增强图像边缘与细节。
sharpen_image(Image, ImageSharp, 'unsharp_mask', 1.5)
直方图均衡化(Histogram Equalization)
- equ_histo_image 将图像灰度分布均衡化,提高图像整体对比度。适用于光照不均的情况。
模板匹配的原理
在待检测图像中,查找与模板图像在形状、纹理或灰度等特征上相似的区域,通过计算待检测区域与模板之间的相似度,确定匹配位置和匹配度
顶帽运算和底帽运算
顶帽运算:用于增强原图像亮部细节,算法:原始的灰度图像的基础上减去开运算(先腐蚀再膨胀)的图像
底帽运算:用于增强原图像暗部细节,算法:原始的灰度图像的闭运算(先膨胀再腐蚀)的基础上减去原图像
Halcon的优缺点
- 优点:高性能 图像处理功能丰富 算法库强大
- 缺点:不是简单的拖拉拽模式,学习成本高,开发成本高。
特征检测
- 定义:识别图像中具有独特性质的点、角、边或区域的过程。
- 关键点:
- 特征点的稳定性
- 特征点的区分性
- 计算效率
Halcon中仿射变化的作用
仿射变换指对图像、边缘、区域进行平移、旋转、缩放和斜切等操作,还原图像本来的平直性
数据图像中的基本特征
颜色特征 纹理特征 形状特征 空间关系特征
像素当量和像素距离
- 像素当量:一个图像像素在真实世界中代表的世界物理长度 单位(mm/pixel)
- 像素距离:两点之间在像素坐标系下的直线距离 单位(pixel)
计算机视觉和机器视觉的区别
对比点 | 计算机视觉 | 机器视觉 |
---|---|---|
定义 | 研究如何让计算机理解和处理图像和视频 | 应用于工业自动化、质量检测等领域 |
目标 | 模拟人类视觉系统,理解图像内容 | 实现自动化检测、测量和控制 |
应用领域 | 广泛应用于医疗、安防、娱乐等领域 | 主要应用于工业生产、机器人等领域 |
精度要求 | 通常较低,关注图像理解和分析 | 通常较高,关注精确测量和检测 |
处理方式 | 基于深度学习、机器学习等算法 | 基于图像处理、模式识别等技术 |
信噪比
信噪比(SNR):有用信号和噪声之间的比例。
重复性
静态重复性:物料不动 执行程序 反复测试32次,查看结果是否相同 动态重复性:物料拿动拿出 更换位置 测试32次
相关性
相同的物料 按照顺序在不同的设备上进行测试 两边的结果数据误差值不能超过0.01
图像预处理的算子
图像增强算子、模糊处理算子、二值化算子、边缘检测算子、形态学处理算子、噪声去除算子、直方图均衡化算子、几何变换算子
HaIcon算子简单列举几个及功能
threshold 阈值分割 connection 连通域分析 sort_region 根据区域的相对位置进行排序 hom_mat2d_identity获取图片的矩阵常量 hom_mat2d_translate 平移矩阵 hom_mat2d_rotate 旋转矩阵 hom_mat2d_scale 缩放矩阵
VisionMaster
VisionMaster的特点
- OCR识别功能无法使用中文。
- 使用九点标定是用的N点标定工具,如果是十二点标定的话要切换为旋转平移标定。
项目相关面试题
相机命名规则
常见的海康相机型号
类型 | 型号 | 说明 |
---|---|---|
CT | MV-CT032G-38GC01-PRO | 适应恶劣工况,支持防水 |
CS | MV-CS016-10GC | 高性价比,适用于一般工业应用 |
CU | MV-CU013-80GM | 低功耗平台,性能稳定,打造同时满足稳定和必要功能的普惠型工业相机产品 |
CH | MV-CH040-A0CM | 高端型,高分辨率面阵相机,针对面板、电子半导体、新能源等行业的高精尖应用开发 |
CL | MV-CL022-40GC | CL 系列为线阵相机系列产品,分辨率覆盖2k ~ 16k |
CB | MV-CB004-10GM-C | 功耗小,板级相机结构紧凑。相比普通工业相机,它的尺寸更小,更易于用户将板级相机集成进自己的产品结构中 |
CI | MV-CI003-GL-N6 | CI系列红外相机是工业应用的高性能红外相机。长波产品采用高灵敏度氧化钒探测器,可呈现温度信息、测量物体温度特征 |
HDMI显微相机 | MV-CM2020C-0H | HDMI显微相机采用高质量成像芯片,内置操作系统,配备HDMI接口,可直接连接显示器,实现图像实时采集 |
CE | MV-CE013-80GM | CE系列是主打高性价比的经济型系列产品,像素覆盖面30万到2000万像素,以卷帘曝光为主 |
CA | MV-CA003-20GC | CA系列是进阶型系列产品,分辨率布局密集,可满足细分应用需求 |
视觉系统单元
图像采集单元 图像处理单元 通信处理单元 终端控制单元
如果想抓拍运动的物体选用什么相机和光源比较好,还是说应该尽量把运动的物体转为静止检测
使用高帧率面阵飞拍或用线扫相机和线光源搭配使用。
- 于高精度检测:如果要求非常高的精度(如微米级别的检测),并且物体的运动速度较快,建议将物体转为静止检测,这样可以确保图像的清晰度和稳定性。
- 对于快速生产线检测:如果生产线速度较快,并且对检测精度的要求不是极端苛刻,使用高速相机、全局快门相机配合脉冲光源进行运动检测是更为高效的选择。
要测的缺陷有划痕,凹坑,粗糙度,壳体有反光,使用什么光源,光路
正常情况下金属外壳是一个平面,没有弧度,选择平行同轴光效果比较好,如果外壳是有弧度的话,选择低角度的光源好一些,最好加上偏振片。
- 检测划痕:可以使用偏振光源结合低角度环形光源,这样可以突出表面细节,同时抑制反光。暗场照明也可以很好地突出划痕等表面缺陷。
- 检测凹坑:同轴光源结合漫射光源是较好的选择,可以使表面凹陷更容易显现,而光滑的反光表面反射会被抑制。
- 检测粗糙度:建议使用漫射圆顶光源,这种光源可以均匀照射表面,减少反光并突出表面粗糙度。
光源
偏振光源(Polarized Light):
- 特点:通过偏振滤光片,可以消除由于反射光造成的眩光,从而获得更清晰的表面图像。配合偏振滤镜,相机也可以减少反射光的干扰。
- 应用:对于有光泽或高反光表面的划痕、凹坑检测非常有效。能够减少反光并突出细微的表面缺陷。
同轴光源(Coaxial Light):
- 特点:同轴光源从相机的光轴方向照射,光线垂直打在物体表面,适合高反光表面。因为光线会沿着物体表面反射回相机,均匀照射可以减少反射造成的亮斑。
- 应用:适合检测平面或光滑反光表面上的微小凹坑和划痕。光源可以有效减少反射光,并帮助突出表面细节。
漫射光源(Diffuse Dome Light 或 平面漫射光源):
- 特点:漫射光源通过均匀分布的光照,避免产生强烈的高光反射,形成均匀的照明效果。特别是圆顶光源(Dome Light)可以从多个角度均匀照射物体,消除大部分反射。
- 应用:适合在反光面上检测凹坑和表面粗糙度。由于光线从各个角度照射,物体表面的反光会被大幅减少,适合处理不规则表面和弧形物体。
低角度环形光源(Low-Angle Ring Light):
- 特点:光源以低角度照射,可以更好地突出物体表面的划痕和凹坑等缺陷,尤其是对于反光的边缘和表面细节有更好的表现。
- 应用:适合检测表面划痕和细微凹陷,在具有反光的金属或抛光表面尤为有效。
光路
倾斜角度照射: 将光源从一个特定的角度(而非垂直于物体)照射,避免正面反射光直接进入相机镜头。这种光路设计可以有效减少光线的强烈反射,从而突出表面缺陷,如划痕或凹坑。
暗场照明(Dark Field Illumination): 采用暗场照明的方式,光源从较低角度照射,而相机则从相对较高的角度捕捉反射光。这种方式非常适合检测反光表面上的微小瑕疵,如划痕和表面粗糙度,瑕疵会在镜头中显示为高亮的区域,而光滑的反光面会显示为暗色区域。
多角度照射: 使用多个光源从不同角度同时照射物体表面,特别是在壳体具有复杂表面时,可以通过多个光源的组合来减少强反光区域。多角度的光路设计可以确保即使一个角度有反光,其他角度也能捕捉到清晰的表面信息。
测量零件尺寸时,背光源和被测工件之间的距离多少为好
一般的背光源越近越好,干扰越少,测量尺寸时建议用平行背光源,边缘受影响少
如何排除透明材质下的灰尘对找边的干扰,项目为找屏幕边缘,但是夹层中存在灰尘,会形成斑点,对找边有干扰,使用什么光源能够有效排除灰尘的反射干扰
在没有金属封边的情况下,条光侧边打,然后在屏幕边缘产生比较亮的光条,距离边缘较远的灰尘没有影响,近距离的可能会产生亮斑,但不会太严重,一般不影响拟合效果
金属罐体如何打光,目前采用两个白色条光打光,效果不是很好,表面反光比较严重,针对这种金属曲面,如何打光才能获得比较好的效果
只想消除反光的话,有两种方法:
- 两个条光上贴上偏振膜,镜头上装上偏振镜,偏振镜调到合适的角度即可
- 改变光源的位置,从左右打光改为上下打光。如果下方没位置就上面打光,光源角度要低(光源贴近样品)
什么光源穿透磨砂膜,检测产品上面要盖一层这种磨砂膜,不能保证完美贴合
x光 目前应用于电池模组的检测,比如小牛锂电池
在使用球积分(碗)光源打光拍图的时候,有没有遇到过图像中间有黑斑的情况,如果遇到的话是怎么解决的
在使用球积分光源时,图像中间出现黑斑通常是由于光源的均匀性不足或光线分布不均匀造成的。解决方法包括:
- 球积分光源配合同轴光源,可以消除中间的阴影区域
- 用标准的白板对相机进行颜色的标定,对阴影区域做亮度补偿,效果也是比较理想的
压焊在黄铜表面的焊点检测,用哪种光源合适
焊点位于金属垫片上,需要拍摄定位出四个焊点,判断焊点是否正常焊正,金属垫片为银白色,表面反光性强,且表面具有一定的凹陷,因此使用碗状光源,利用其多角度,全方位的慢射光打亮样品表面,去掉其表面凹陷干扰的同时,可以突出焊点,拍摄出的图像具有很高的对比度,但碗状光源中心具有一圆形开孔,会使拍摄的图像中心形成一个圆形的阴影区,因此我们在碗状光源上加装一个同轴光源,即可达到拍摄要求
红光与蓝光我了解的区别就是在波长上不同,但是在实际的运用中,都是根据效果在选择,它们根本的区别是什么
- 波长:比如说拍手机上的摄像头,你想拍摄头表面的玻璃就用波长短反射强的蓝光,想拍里面就用波长长的红光
- 颜色互补:比如拍摄红色色的物体,用红光拍摄出来就是亮的,用蓝光拍出来就是暗的,具体还是根据你想要的效果去选择搭配
图片红色方框区域内是肉眼可见的条形区域(由于本身颜色比较淡)在白色光源下拍不到其存在,这种情况该如何打光才能改善
蓝光或者绿光,通过互补光将其打光为黑色,突出显示。
对如下图片所示的电子元件(包装在料袋内)进行机器视觉缺陷检测,料袋上的透明塑料膜造成的反光影响会比较大,类似这种的场景的光源如何选型比较合理
用红外光源低角度打光,这样的项目一般用带角度的环形光,不可垂直打光或高角度打光,避免直接反射造成的干扰。或者者使用偏振光源,配合偏振镜头,调节角度来消除反光。
检测泡罩包装药片的质量,缺陷种类包括:无药片,药片破碎,药片上存在杂质,铝板与泡罩热合不良等缺陷
- 使用偏振片减少镜面反射: 在泡罩包装中,塑料泡罩和铝箔层都可能产生强烈的镜面反射。偏振光可以减少这种反射,从而让相机更清晰地看到泡罩内的药片状态。通过使用偏振片,可以消除由材料表面产生的高光点,使图像更加清晰,便于后续的图像处理。
- 增强对比度: 对于某些缺陷,如药片上的杂质或药片本身的颜色变化,偏振光可以帮助增强这些特征与背景之间的对比度,使得缺陷更容易被检测出来。
- 改善图像质量: 在某些情况下,偏振光可以改善图像的整体质量,减少不必要的光斑或阴影,使得图像更均匀,从而提高检测的准确性。
- 适应特定材料: 泡罩包装材料可能是半透明的,而偏振光可以更好地穿透这些材料,同时减少散射光的影响,使得相机能够更清楚地看到内部情况。
相机拍照时间一般是多少
100ms或者是200ms跟相机是多少万像素和帧率有关,1000w以内的都可以说用100ms,1000w以上的都可以说是150ms或200ms
视觉检测时间
100ms-500ms,看检测难度,简单点的计算坐标可以说100ms,复杂的缺陷检测可以说200-300ms
项目中用了几个相机
如果是测量类或者比较简单的项目,用两个相机,一个相机的CT(单次检测的时间)不够,CT是多少,一小时4000,单个相机不够
引导项目,一般是两个到三个,如果是多种缺陷检测2-4个,不同的缺陷类型用不同的光源或者检测的位置略有不同
项目里面负责什么
负责打光,写程序,写视觉算法,调机,或者全部都是自己完成
有没有调过机
相机连接不上是怎么解决的? 先检查指示灯状态看看是不是绿灯一般正常情况下指示灯正常都是绿的,如果是红灯闪烁或者指示灯不亮,可能是相机与设备之间的连接存在问题
测量不稳定是什么原因导致的? 首先检查是不是测量仪器本身的问题看看元器件是否老化和零部件损坏,然后在检查是否是人为因素可能因为用户在使用测量仪器的时候操作不当导致的,接着检查供电电压是否稳定 如果电源质量不稳定也会影响测量仪器的正常工作,最后考虑一下环境因素 例如:电磁场干扰 或者温度和湿度的变化太大
贴合不稳定是怎么解决的?
- 视觉方面:检查相机镜头,有没有锁紧,重新标定
- 机构方面:机台不水平,有晃动,吸料不稳,产品吸的不平,破真空异常
- 首先我们要先检查并调整一下机台水平度,使用水平仪确保机台在各个方向上都处于水平状态
- 然后处理机台晃动的问题 ,检查机台各个部件的螺丝是否紧固,特别是关键部位的固定螺丝
- 接着优化吸料系统,我们要去检查吸料装置确保吸料装置(如:吸盘,真空泵等)处于良好的工作状态 ,调整吸料参数,根据产品的材质和形状调整吸力大小,吸附时间等
- 如果吸的不平的话我们可以优化产品定位机构和调整,确保产品在吸附时能准确地定位在指定位置,避免发生偏移
- 破真空异常 首先检查真空系统 检查真空系统的各个部件是否完好无损,接着调整真空的控制逻辑和参数设置
- 来料方面: 产品本身误差大,例如尺寸公差±0.15,产品本身波动在0.2,导致贴合不稳定
日常负责的是什么?工作过程中遇到的问题是什么?如何解决的?
调试同上 如果可以独立做项目同下
有没有单独做过项目
简述流程
- 如果单独做过项目,尽量说是小项目,只有一台机,用了一个视觉一个电控一个售后
- PM给到需求,根据产品的公差和大小确定相机
- 去现场打光测试,给报告方案
- 写程序,调机
打光一般用多长时间
- 根据产品的需求不同和测量的尺寸多少不同用的时间不一样
- 如果尺寸测量,可以说半天到一天,然后作出数据报告
- 如果是外观检测,根据不同种类的缺陷,选用不同的光源组合,可能3-5天
- 项目周期是多久:一个月左右
做项目流程
- 拿到需求
- 根据公差带选择合适硬件
- 打光测试
- 出视觉方案
- 如果项目确定能做就和机构的沟通检测方案和相机的安装方式
- 和电控人员沟通通讯内容
- 写程序
- 现场调试
调试流程
- 硬件安装调试
- 相机镜头安装:确保相机与镜头接口匹配(C/CS接口),镜头螺丝锁紧
- 光学系统调试:
- 调整相机安装高度和拍摄角度
- 确定合适的焦距和工作距离
- 调整光源位置和亮度,优化成像效果
- 确保图像清晰度和对比度满足检测要求
- 视野与标定
- 视野调试:根据检测需求设置合适的视场范围
- 畸变矫正:使用标定板进行相机畸变校正,确保测量精度
- 精度验证:
- GRR测试:进行重复性(Repeatability)和再现性(Reproducibility)测试,通常要求GRR<10%
- 相关性验证:与标准测量设备对比,确保测量结果的准确性
- 机械手引导系统(如适用)
- 手眼标定:
- 确定机械手拍摄点位
- 执行九点标定,建立像素坐标系与机械手坐标系的转换关系
- 验证标定精度,确保引导误差在允许范围内
- 旋转中心标定(如适用)
- 通过机械手三个不同角度拍摄,获取特征点坐标
- 拟合圆心,确定旋转中心位置
- 使用实际产品验证贴合精度
- 工艺能力验证
- CPK测试:进行过程能力分析,通常要求CPK≥1.33
- 稳定性验证:连续生产验证系统稳定性
- 边界条件测试:测试产品公差范围内的极限情况
- 缺陷检测优化
- 样品收集:收集各类良品和不良品样本
- 算法优化:
- 根据实际缺陷特征调整检测参数
- 优化光源配置和图像处理算法
- 设置合理的判定阈值,平衡检出率和误判率
- 验证测试:使用大量样品验证检测效果
- 系统验收
- 最终精度确认:确保所有指标满足客户要求
- 操作培训:对操作人员进行系统使用培训
- 文档交付:提供操作手册、维护指南等技术文档
如果做过引导项目
- 单相机引导
- 贴合精度是多少? 例:客户要求的精度是±0.2mm
- 贴合完成后数据波动是多少? 贴合完成后拍照检测 数据波动范围在±0.1mm
- 如果问有没有做过更高精度的? 可以回答说没有
- 怎么标定的? 九点标定
- 怎么求旋转中心?
- 两点法(拍一个点,然后旋转180°,再拍一个点,两个点连线的中点就是旋转中心)
- 三点法(三点拟合一个圆,圆心即旋转中心)
- 五点法(拍摄多个点,然后根据最小二乘法拟合一个圆)
- 前两种方法,由于其适用的场景很窄,所以一般使用的都是五点法,因为FA镜头的畸变存在,这五个点尽量分散能覆盖掉一半的周长最好,千万不要只用很小的一段周长范围去拟合圆,这样求出的旋转中心会偏的很离谱。
- cpk能做到多少? 1.33
CPK值 | 过程能力评价 | 说明 |
---|---|---|
CPK ≥ 2.0 | 优秀 | 6σ水平,极低缺陷率 |
1.67 ≤ CPK < 2.0 | 充分 | 5σ水平,很好 |
1.33 ≤ CPK < 1.67 | 良好 | 4σ水平,可接受 |
1.0 ≤ CPK < 1.33 | 勉强可接受 | 需要改进 |
CPK < 1.0 | 不充分 | 过程能力不足 |
请描述下你的引导流程
说下几个相机,怎么做的标定和旋转中心即可,比着上面的问题挑几个回答
- 调整相机的位置,确定相机安装高度和视野
- 调整机械手拍照位置
- 做九点标定和旋转中心
- 拿样品测试贴合效果
- 引导项目中一般用什么标定
- 九点标定
九点标定法是基于什么实现的
用visionpro的CalibNpoint工具
相机知道的是像素坐标,机械手是空间坐标系,所以手眼标定(九点标定)就是得到像素坐标系和空间机械手坐标系的坐标转化关系。 手眼标定作用:建立相机坐标系和机械手坐标系之间的关系,即给机械手装上眼睛,让它去哪就去哪
九点标定怎么做
机械手吸取产品或者标定块移动九个位置,相机分别拍九次照获取九个像素坐标,把九组机械手坐标对应的视觉坐标一起填入VisionPro的CalibNpointToNpointTool工具,运行校正获取标定结果
在引导项目中你是如何找旋转中心的
机械手三个角度,每一次拍摄一张照片,通过视觉工具抓取中心点坐标,三个点拟合一个圆,圆心就是旋转中心 如果问旋转多少度,可以说15度或者20度,角度过大产品就会超出视野
如何验证轴或机械手走位精度
- 机械手吸取产品重复移动到相机拍照点位
- 相机拍照抓取特征点坐标
- 查看坐标是否偏差过大
生产过程中贴合不稳定是什么原因
任何视觉项目检测中出现的问题都可以从三个维度分析,下面是引导的机台出问题的解决方案
- 产品本身有问题
- 上面有脏污,破损导致视觉抓错;
- 定期清理产品表面,确保无脏污,异物或破损
- 产品本身容易变形导致视觉抓错
- 材料选择:选用不易变形的材料或加强固定措施,减少变形带来的影响
- 机构有问题
- 机台水平没打好
- 校准设备:检查并调整机台水平,保证所有部件都在正确的水平线上工作
- 机械手水平和贴合平面水平不一致
- 同步调整:确保机械手和贴合平面的水平一致性,避免因位置偏差造成的贴合不准
- 破真空异常,机械手完全贴合产品,往回移动的时候带动产品导致有误差
- 气压检查:检查破真空系统是否正常工作,确保机械手在贴合产品后能平稳释放而不带动产品
- 相机松动,没有锁紧
- 确保相机牢固安装,放置松动影响视觉检测精度
- 视觉问题
- 镜头螺丝没有锁紧导致聚焦不够清晰
- 检查并紧固镜头螺丝,确保图像聚焦清晰
- 重新做九点标定和旋转中心
如果在现场调试期间,发现现场成像效果不理想,应该怎么做
调整成像,检查曝光是否合理,镜头光圈大小、安装高度
检测光源
- 确保选择了合适的光源,不同物体表面特性和检测需求可能需要不同的光源
- 调整光源的亮度,避免过亮或过暗
- 检测光源的位置,不同角度的光照可以改善某些细节的显现
- 相机参数调整
- 相机参数调整
- 曝光时间
- 增益
- 分辨率确保分辨率是否合理,高分辨率会增加处理时间,可能会影响实时性
- 镜头和焦距调整
- 确定焦距距离
- 确保相机正确对焦,以保证图像清晰度
- 机械装置检查
- 相机与工件的相对位置是否匹配
- 确保现场没有机械振动或者相机支架松动影响图像清晰
- 图像处理与算法
- 在图像处理前进行适当的预处理操作
- 外部因素干扰
- 环境光干扰
- 尘埃或者污渍
3C从业经验
结合电脑、通讯、和消费性电子三大科技产品整合应用的资讯家电产业
泡棉贴合
公差±0.2 精度0.02 视野是30mm*25mm 用了500w相机 贴合的公差波动在±0.1左右
做项目的过程中遇到的问题:
- 环境光照变化:机器视觉系统对外界光线非常敏感,如果工作环境中的光照条件不稳定,可能会影响图像的质量,从而影响测量的准确性。
- 相机分辨率与焦距调整:为了实现高精度的检测,需要选择合适的相机分辨率,并且正确设置镜头的焦距,以确保能够清晰地捕捉到泡棉贴合区域的细节。
- 泡棉材质的不一致性:泡棉材料可能存在一定的厚度和密度差异,这会导致即使是在相同的加工条件下,不同的泡棉也会有不同的表现形式,从而影响贴合的一致性。
- 边缘检测与定位:泡棉的边缘可能不够清晰或存在细微的不规则,这对边缘检测算法提出了挑战。如果不能准确地检测到泡棉的位置,那么后续的贴合操作就会出现偏差。
- 贴合过程中的移动:在泡棉贴合过程中,任何微小的移动都可能导致最终位置的偏移。这要求控制系统必须具备很高的稳定性和响应速度。
- 软件算法优化:为了达到高精度的要求,可能需要定制化的图像处理算法来提高识别的准确性和鲁棒性。此外,还需要考虑算法的计算效率,以保证实时性。
- 温度和湿度的影响:温度和湿度的变化也会影响泡棉的物理特性(如膨胀或收缩),进而影响贴合精度。
- 机械部件的磨损:随着时间的推移,机械臂或其他运动部件的磨损可能会导致重复定位精度下降,这也是需要定期维护和校准的原因之一。
铁氧体尺寸测量
测了10个数据 产品尺寸50mm*30mm 公差±0.1 选用了**w像素相机 进行测量
做项目的过程中遇到的问题:
- 像素分辨率不足:如果相机的像素分辨率不足以分辨出0.1mm的公差范围,那么测量结果将不够精确。例如,如果使用的是一个低分辨率的相机,它可能无法提供足够的细节来准确测量尺寸。
- 照明不均匀:照明条件不均匀会导致某些区域的对比度降低,从而影响边缘检测的准确性,进而影响尺寸测量。
- 边缘检测困难:铁氧体的边缘可能不够清晰或者存在反光,这会使得边缘检测算法难以准确识别边界。
- 相机标定误差:如果没有正确标定相机,或者标定参数随时间发生漂移,这会导致测量结果不准确。
- 背景干扰:如果背景中有其他物体或者杂乱无章的图案,可能会影响图像处理算法的性能。
- 振动和运动模糊:如果测量过程中有轻微的振动或铁氧体移动,这会导致图像模糊,从而影响测量精度。
解决方案:
- 选用高分辨率相机:确保相机的像素足够高,可以分辨出至少0.1mm的变化。例如,对于50mm×30mm的尺寸测量,可以选择具有较高像素的工业相机,并适当调整视场大小以确保足够的分辨率。
- 优化照明系统:使用均匀的背光或侧光照明,减少阴影和反射,提高边缘对比度。
- 高级边缘检测算法:使用更先进的边缘检测算法,如亚像素级别的边缘检测技术,以提高测量精度。
- 相机标定:在使用前进行精确的相机标定,并定期重新标定以保持测量准确性。
- 背景处理:通过软件算法去除背景干扰,比如使用背景减除技术或者固定背景模板进行图像分割。
- 抗振措施:确保测量平台稳固,必要时可增加减震装置,同时控制铁氧体的放置稳定性。
- 环境控制:尽量在一个稳定的环境中进行测量,控制温度和湿度的变化。
UV胶水检测
用UV光(紫外线)拍摄胶水 提取颜色,然后blob检测
现在有个产品视野比较大,长度在200mm左右,精度要求比较高,我该怎么去测量
使用两个500w相机(满足精度要求),用带二维码的菲林片进行相机标定,把相机标定在同一空间就可以进行测量
如果不想用两个相机就想用一个节省成本,可以使用一个相机和一张大的菲林片,移动相机设置两个拍照位置拍照标定。如果再问回答不知道
什么是GRR,什么是相关性
GRR一般做到10%以内,相关同样
GGR是一个统计工具,用于评估测量系统的变异性。GRR 分析通常用来确定一个特定的测量过程是否足够精确以满足产品的公差要求。它通过分析不同操作者使用同一设备对相同部件进行多次测量的结果来衡量测量系统内的变异性
重复性(Repeatability)指的是同一个操作者使用相同的设备对同一零件的同一特性进行多次测量时结果的一致性。这反映了测量过程中随机误差的影响。
再现性(Reproducibility)则关注不同操作者之间使用相同的设备对同一零件进行测量时结果的一致性。这考虑了由于操作者差异导致的系统误差。
相关性(Correlation)是一个统计学概念,用来描述两个或多个变量之间的关系强度和方向。在机器视觉中,如果涉及到数据分析,相关性可能被用来表示图像特征或其他测量数据点之间的相互依赖性。例如,在检测过程中,一个特定的缺陷模式与生产条件之间的相关性可以帮助识别问题的根源。
机械手精度是多少
用的四轴机械手,一般是0.02mm,即两条左右 0.01mm,北方习惯称“道”,南方习惯称“丝”,台企习惯称“条”
测量圆珠笔直径
选背光,打轮廓出来
包装logo字体,有没有印反,用什么方式实现
模版匹配
检测划痕用什么光源
- 环形光(Ring Light)环形光从多个角度均匀照射目标区域,有助于减少阴影并突出表面细节。这对于检测平坦表面上的划痕非常有效。
- 同轴光(Coaxial Light) 同轴光是从镜头轴心方向发出的光,可以减少反射干扰,适用于检测高反光表面或透明材料上的划痕
- 条形光(Bar Light)或线性光(Linear Light) 这种光源通常沿着一条直线分布,可以用于照亮较大的区域或特定的检测路径,对于长条形划痕检测很有帮助。
缺陷检测常用的打光类型
同轴+环光组合使用
- 环形光(Ring Light)
- 用途:适用于平面或轻微曲面物体的检测,能够提供均匀的照明,减少阴影。
- 适用缺陷:划痕、斑点、裂纹等。
- 同轴光(Coaxial Light)
- 用途:减少镜面反射,适用于高光泽度或反光表面的检测。
- 适用缺陷:微小划痕、指纹、灰尘颗粒等。
- 条形光/线性光(Bar Light / Linear Light)
- 用途:适用于较大区域的照明,可以通过调整角度来强调某些特征。
- 适用缺陷:长条状划痕、接缝不齐等。
- 背光(Backlighting)
- 用途:从被测物体背后照亮,通常用于边缘检测或透明物体内部缺陷检测。
- 适用缺陷:孔洞尺寸偏差、透明材料中的杂质或气泡等。
接触过什么品牌的PLC
西门子、施耐德、三菱电机、AB、伦茨、绘川、台达、中控、信捷
- 西门子:西门子是全球领先的自动化解决方案厂商,plc系列以稳定性和功能强大著称,适用于中大型自动化控制系统
- 施耐德电气:市场占有率较高,特别是在能源管理、基础设施和工厂自动化等领域,具有高可靠性和良好的网络通信功能
- 三菱电机:性价比高,易与编程,结构紧凑,广泛应用于中小型自动化控制场合,FX系列适合小型控制系统,Q系列适用于从小型到大型的控制系统
什么是GRR和CPK?请描述一下
GRR:
- 静态重复性:产品放置不动拍摄测量尺寸 ,反应了视觉算法精度有没有问题
- 动态重复性:产品取放拍摄测量尺寸,反应了设备的稳定性
- 测量重复性的意义:其目的在于可以根据测试的数据研判机台的硬件是否存在问题,定位是否足够准确,以及算法是否存在局限性,在拿到GR&R数据后,应当找出跳动最大的数据,追溯该笔数据所对应的点云以及其所在的位置,对其进行相应的分析,只有当确保自己的机台在测试相应数据时不会出现偏差,才能去与对应的的标准机进行对标 GRR一般做到10%以内。
- 相关性的要求由客户给定,同时测量的次数,物料的片数,也严格按照客户要求进行,根据测量项来确定偏移量(offset)和线性的斜率(ratio),在针对偏移量进行补偿以后,测量值与真值所拟合的线性斜率越接近1,说明我们的机台与标定机结果越符合。
CPK:
- 反应了设备过程是实际加工能力,CPK越好,贴合越稳定
可以回答之前做到1.33
机械手贴合位置补偿
偏差分析 发送坐标:(100.20, 50.30, 90.00) 实际到达坐标:(100.25, 50.22, 90.55) 坐标偏差: X方向:100.25 - 100.20 = +0.05 Y方向:50.22 - 50.30 = -0.08 角度:90.55 - 90.00 = +0.55 补偿策略 当每次贴合都存在固定偏差时,可以设定补偿值:
offsetX = -0.05; // X方向补偿(与偏差相反) offsetY = +0.08; // Y方向补偿(与偏差相反) offsetR = -0.55; // 角度补偿(与偏差相反)
// 补偿后的坐标计算 finalX = targetX + offsetX; finalY = targetY + offsetY; finalR = targetR + offsetR;
补偿原理 通过在发送坐标时预先加上与偏差方向相反的补偿值,使机械手实际到达的位置与目标位置一致,从而提高贴合精度。
防呆
即预防措施,例如贴电池的时候,我们本来要拍正面计算长宽,但实际吸取到产品的时候我们拍到的是反面,这时候加一步预防措施,判断相机是否是正面,如果不是,就NG不再执行后续组装的操作。
相机硬触发的三种接线方式
方式一:并行触发
- 接线方式:同一I/O信号同时触发相机和光源控制器
- 特点:相机和光源同步触发,时序一致
- 适用场景:对同步性要求高的应用 方式二:串行触发(相机优先)
- 接线方式:I/O信号触发相机,相机输出信号接光源控制器
- 特点:相机先响应,然后触发光源
- 适用场景:需要相机控制光源时序的应用 方式三:串行触发(控制器优先)
- 接线方式:I/O信号触发光源控制器,控制器输出信号接相机
- 特点:光源控制器先响应,然后触发相机
- 适用场景:需要光源稳定后再拍摄的应用
选择建议 并行触发:适合对时序要求严格的高速检测 相机优先:适合需要精确控制曝光时机的场景 控制器优先:适合需要光源预热或稳定时间的场景
工业选型案例
工业相机型号已经选择好:相机芯片尺寸为2/3,C接口,500万像素,视野:100*100mm 工作距离:500mm
镜头接口:首先工业相机镜头要和工业相机接口一致,所以这里也选c接口 镜头大小:遵循镜头大小要大于相机的芯片大小,所以这里的镜头尺寸最少也要支持2/3 镜头分辨率:镜头的分辨率要高于相机的分辨率,所以选择500万像素以上 焦距:500(WD)*8.8mm(靶面尺寸 H)/ 100(FOV) =44mm 镜头放大倍率:8.8(芯片水平长度)/100(视场) = 0.088
工件大小为75 * 40mm,一次需要拍摄单个工件,选用500W OPT相机(芯片尺寸5.7*4.3mm,分辨率 2592 * 1944),机构空间限制为镜头工作距离在600-900mm之间,请问大概选择多大焦距的镜头?
为了选择合适的镜头焦距,我们需要考虑工件的尺寸、相机的芯片尺寸以及镜头的工作距离。这里,我们已知工件的大小为75 * 40mm,相机的芯片尺寸为5.7 * 4.3mm,分辨率为2592 * 1944,以及镜头的工作距离在600-900mm之间。
首先,我们需要计算相机芯片上每个像素代表的实际尺寸,这通常被称为“像素尺寸”或“空间分辨率”。由于相机的分辨率为2592 * 1944,芯片尺寸为5.7 * 4.3mm,我们可以分别计算水平和垂直方向上的像素尺寸:
水平像素尺寸 = 5.7mm / 2592 ≈ 0.0022mm/pixel 垂直像素尺寸 = 4.3mm / 1944 ≈ 0.0022mm/pixel(这里为了简化计算,我们假设水平和垂直方向的像素尺寸相同,实际上可能略有差异)
接下来,我们需要考虑如何将工件完整地成像在相机的芯片上。由于工件的长边为75mm,我们需要选择一个焦距,使得在镜头的工作距离内,工件的长边能够覆盖相机的芯片长边。这里,我们可以使用简单的比例关系来估算焦距:
焦距 = (工作距离 × 芯片长边尺寸) / 工件长边尺寸
由于工作距离在600-900mm之间,我们可以选择一个中间值(如750mm)来进行估算,但请注意,这只是一个近似的起点,实际焦距可能需要根据镜头的具体性能进行调整。
焦距 ≈ (750mm × 5.7mm) / 75mm ≈ 57mm
然而,这个估算值可能并不完全准确,因为它忽略了镜头的其他特性(如畸变、场曲等)以及实际成像时的各种因素。因此,在实际应用中,我们应该根据镜头的具体规格表或咨询镜头制造商来选择合适的焦距。
此外,由于镜头的工作距离范围较宽(600-900mm),我们可能需要选择一个变焦镜头或至少两个定焦镜头来覆盖整个工作距离范围。如果只能选择一个镜头,并且需要在这个范围内都能获得清晰的图像,那么我们应该选择一个焦距稍长且能够在整个工作距离内保持良好成像质量的镜头。
综上所述,基于给定的信息和估算方法,我们可以初步选择一个焦距约为57mm的镜头作为起点,但具体选择还需要根据镜头的实际性能和应用需求进行调整。
在封闭的车间里,有日光灯照明导致图像明暗闪烁,请说明都有哪些方法可以解决问题;请尽可能多的列举出来
在封闭车间内,日光灯照明导致的图像明暗闪烁问题,主要源于日光灯的频闪特性以及相机或摄像设备的曝光设置与灯光频率不匹配。
更换照明设备:
- 使用无频闪的LED灯:LED灯通常具有更高的频率,且很多LED灯设计为无频闪,可以显著减少图像闪烁。
- 调整日光灯类型:如果必须使用日光灯,可以选择高频电子镇流器日光灯,其频闪频率远高于传统日光灯,有助于减少闪烁现象。
调整相机或摄像设备设置:
- 调整快门速度:将相机的快门速度设置为与灯光频率相匹配或为其整数倍,可以减少因曝光时间与灯光闪烁周期不一致而导致的闪烁。
- 启用防闪烁功能:许多现代相机和摄像机都配备了自动防闪烁功能,该功能可以自动检测并调整快门速度以匹配灯光频率。
- 调整曝光模式:使用手动曝光模式,并仔细调整曝光参数,如ISO、光圈和快门速度,以获得更稳定的图像。
使用滤镜或遮光罩:
- 使用柔光罩或扩散板:这些设备可以分散光线,减少光线直接照射到相机镜头上产生的闪烁效应。
- 安装偏振镜:虽然偏振镜主要用于减少反光,但在某些情况下,它也可能有助于减少因光线波动引起的图像闪烁。
优化车间环境:
- 增加照明设备数量:通过增加照明设备,可以减少每个灯具的负载,从而降低闪烁的可能性。
- 均匀分布照明:确保车间内照明分布均匀,避免局部过亮或过暗,这有助于减少因光线不均引起的图像问题。
使用图像处理软件:
- 后期处理:在图像拍摄后,可以使用图像处理软件(如Photoshop)进行后期处理,通过调整亮度、对比度和色彩平衡等参数来减少闪烁现象。
视频稳定技术:对于视频素材,可以使用视频编辑软件中的稳定技术来减少因光线闪烁导致的画面抖动。
寻求照明专家建议:咨询照明领域的专家,了解如何根据车间具体情况选择合适的照明设备和布局。
与相机制造商联系:如果问题持续存在,可以联系相机或摄像设备的制造商,了解是否有特定的设置或固件更新可以解决此问题。
自我介绍+工作经历?大学所学的专业
自我介绍:
- 面试官你好我叫XXX,来自XXX,拥有两年的机器视觉经验,目前专注于视觉检测领域。我热爱技术创新,尤其擅长使用VisionPro结合C#进行编程和调试,能够高效地解决实际问题。在大学期间,我主修电子信息工程技术,通过这一专业的学习,我对电子电路、信号处理以及计算机编程等领域有了全面的理解。工作之余,我喜欢打羽毛球,保持活力和健康。
工作经历:
- 在过去的两年里,我一直从事机器视觉相关的工作,主要负责视觉检测系统的开发和调试。在项目中,我利用VisionPro进行图像处理,结合C#实现自动化检测流程,确保产品质量的稳定性和生产效率的提升。通过这些实践,我积累了丰富的项目经验,尤其在视觉算法的优化和系统集成方面,具备较强的解决问题的能力。
日常负责的是什么?工作过程中遇到的问题是什么?如何解决的?
可以说负责机台调试,vpp修改、框架程序功能模块的修改,硬件选型、打光出方案,写程序和视觉算法,调试流程一整套流程都会
调试的程序是ok的,下一步做检测吗?
比较宽泛,可以介绍自己做项目的流程:
- 比如测量的就是做相机畸变校正,调试写好的视觉算法程序,做数据GRR相关性等数据
- 引导的就是做N点标定,旋转中心,调试贴合程序,做CPK等数据
- 外观检测就是收集不良品,训练模型、优化模型以达到可以检测的水准
如果问优化模型需要多久?
回答:根据提供的不良品的种类和数量,大概在一至两周左右、如果没有这种不良品可以和客户沟通手动制造一些这种不良,或者先行生产有人工进行复判
之前检测的哪些地方,有哪些缺陷?
回答:焊点检测 就是少锡、锡多、烧伤、这些用深度学习检测,锡高用3D检测,尽量不提虚焊
如果非要提虚焊:就说那种图像上呈现面积减小或图像上能呈现的可以检测,其他的没有特别好的办法,一般都有提前和客户沟通这种事情、不做虚焊检测 金属件例如type-c头:检测划伤、碰伤、脏污
手机中框:划伤、碰伤、脏污、pad氧化异色
过检率?漏检率?
过检率在3%、尽量在5%以下、 漏检在0.2%以下
可以说过检和漏检也跟制程息息相关,有时候前面制程不良会导致产品有色差或者某些地方和之前不一样导致误判
如何将过检,漏点从28调整到0.1?漏检30片,如何处理才能做到0.1?
- 深度学习训练模型优化模型
- 传统的就尽量优化视觉算法,或者观察是不是产品的问题,机构的问题一一解决
比如说你做了这个东西,客户让你写分析方案能否写出来?(这个问的不是会不会写详细的报告)
回答:可以的,就把调机用的分析思路写出来
对于图像处理有没有试过一些图像分类这些东西
回答:有用深度学习,对图像进行分类
有没有了解过深度学习
深度学习是一种基于人工神经网络的机器学习技术,尤其适用于处理大规模数据和复杂任务,如图像识别、语音处理和自然语言理解。它通过多层神经网络(通常包含数十到数百层)自动提取数据中的特征,能够实现比传统机器学习方法更高的精度。
在机器视觉中,深度学习也被广泛应用于缺陷检测、分类、物体识别等任务。深度学习模型可以通过大量标注数据进行训练,自动学习到检测缺陷所需的特征,不再依赖手动设计的特征提取算法。通过标注、训练模型、优化模型,最后导出视觉处理算法。
简单来说通过大量标注和训练,不断优化视觉模型。使得算法能够做到自动识别相同种类的特征。
- 主要应用类型
- 分割(监督模式)
- 判断图像中的哪些像素属于哪些图标,对图像中复杂缺陷进行分割,学习NG样本。
- 视野中有很多目标物体,用定位模块进行定位
- 目标物体有角度、半径识别需求,用定位模块进行角度估计
- 任意形状目标高精度定位
- 非监督分割
- 用于NG样本不易得而OK样本易得的场景,通过学习OK样本识别并分割图中存在的缺陷。
- 适用于背景一致性较好的场景,如铁丝网、布匹检测等
- 宏观缺陷检测(检测低频严重缺陷)
- 定位
- 确定目标在图像中的位置。
- 检测
- 定位目标并分类。
- 分类
- 判断图像所属类别,一般搭配定位和分割使用。
- OCR
- 识别字符。
- 深度学习是构建多层神经元网络结构,他是会自动从原始数据中提取特征并且进行学习。他的主要核心是:构建多层网络结构,包括输入层,隐藏层和输出层,通过权重和偏执链接各层,并利用传播算法来进行训练。
- 前馈神经网络(Feedforward Neural Networks):信息单向流动,从输入层到输出层,中间可以有多个隐藏层。
- 循环神经网络(Recurrent Neural Networks, RNN):具有反馈环路,能够处理序列数据,如时间序列分析或自然语言处理。
- 卷积神经网络(Convolutional Neural Networks, CNN):特别适用于图像和视频分析,通过卷积层来提取空间特征。
- 深度信念网络(Deep Belief Networks, DBN):由多层受限玻尔兹曼机(RBM)堆叠而成,通常用于特征提取和降维。
- 自编码器(Autoencoders):用于数据的压缩表示,通过学习输入数据的高效编码和解码。
- 生成对抗网络(Generative Adversarial Networks, GAN):由生成器和判别器组成,能够生成新的、与真实数据相似的数据样本。
AI相比传统算法的优势
- AI可以解决传统算法解决不了的问题:
- 传统算法对图像的灰度信息进行提取,对于边界不清晰,灰度值对比不明显的缺陷检测效果差
- AI检测基于数据驱动进行特征提取,对成像的要求没有传统算法高
- 对形态、纹理、颜色的提取能力强
- 对于边界不清晰、灰度值与周围差异较小的缺陷,以及产品表面为曲面导致亮度不一的情况,传统算法几乎无法检测或者算法开发困难
- AI的劣势
- AI精度不如传统算法高,不适合解决测量类的需求:对于定量的检测任务,AI检测精度不如传统算法高。
- 传统算法精度达到亚像素级别,例如当检测目标边界清晰,对比度明显时,AI得到的面积、位置等信息不够准确,会有3个像素左右的偏差,因此测量类的需求不适合AI解决。
- AI落地流程
- 样本收集阶段
- 需求分析:获取一定量的图片,梳理和分解需求,根据检测要求,成像效果评估AI是否可行
- 整体方案:整体算法方案,包括模型数量,分别采用哪种算法、分别检测哪些缺陷、训练和推理时间,确定相应的硬件配置(主要是显卡)
- 小批量验证:根据已有的样本,训练AI模型,初步验证模型效果
- 初步建立模型
- 建立模型:扩充样本,确立各类缺陷的标注标准,创建AI模型
- 优化模型与方案: 根据模型效果和检测需求,不断优化模型过检和漏检,保证检出,对检测效果不好的可以考虑调整方案
- 实际测试:使用检测软件加载模型,试跑实际的产品,跑通检测流程
- 批量验证阶段
- 批量试跑:使用检测软件试跑线上的产品,针对OK的误检、NG品的漏检,继续优化模型,或者调整方案标准细化,针对新出现的类型产品缺陷特征,继续细化标注标准。
- 试运行阶段
- 上线试跑:上线试跑大量产品,对模型问题进行查漏补缺。
AI模型迭代优化的流程
三个原则:
- 构建更好的样本集
- **样本的数量、比例和质量(代表性)。**收集样本阶段需要注重这三项,要让训练集足够丰富
- 确立更清晰的标准
- 基于图像的目视标准,人言可区分。AI作为数据处理工具,要求缺陷能够基于图像肉眼可识别
- 选择更合适的参数
- **主要是数据处理参数以及测试参数。**一般参数在一开始的阶段已经确定,后续优化基本也很少发生变化
- 总结:模型不断迭代优化的过程,是样本集不断完善的过程,也是标准定义逐渐清晰的过程
三个问题:
发生漏检,过检,先问三个问题
- 数据:数据训练集中是否有类似缺陷的产品?
- 标注:是否类似特征(NG或OK的特征)的标注有误?
- 成像:该缺陷与干扰在成像上能否区分?
打样过程会记录问题点,怎么记录,设备出现问题处理的流程
会记录,记录到一个问题本上,查看问题出现在哪里,一步步排查问题点,从而解决问题
接触哪种类型的相机
面阵相机(Area Scan Camera):适合捕捉二维图像,通常用于需要获取整个场景或物体的图像检测任务,广泛应用于物体识别、尺寸测量等场景。 线扫相机(Line Scan Camera):通过逐行扫描的方式获取图像,适合在传送带或高速移动的场景中使用,尤其适合检测长条状或连续移动的物体,如纺织品、纸张等。
缺陷检测过程?缺陷检测用几个相机检测?什么类型的相机?相机规格
回答:
相机:海康890W和1200W相机,根据不同类型的缺陷种类可以说两到四个相机
比如说 划伤用一个、脏污用一个、IC检测用一个、或者就是产品用有金属有塑料,不同的类型需要增加相机
也可说CT要求高,用了四个相机,检测的内容都是相同的
简历写的项目怎么检测怎么定位?定位前期准备工作做了什么
视觉方面,就是相机N点标定,旋转中心,验证机械手运动点位的重复性
定位出现什么问题?你会怎么排除?
- 光照均匀
- 图像分辨率不够
- 图像噪声
- 目标特征不明显
- 相机校准不准
- 算法选择不当
请问你对visionPro了解到什么程度
常规的视觉检测和引导都没问题
VisionPro基本功能
- 视觉工具:VisionPro 提供了丰富的视觉工具库,包括图像预处理、模式匹配、边缘检测、测量工具等。用户可以通过这些工具构建复杂的视觉应用,如物体识别、对位、尺寸测量等。
- 图像处理算法:VisionPro 包含先进的图像处理算法,如基于灰度的模板匹配(PatMax),它可以用于准确定位物体,即使在不同的旋转、缩放或部分遮挡下,也能取得较高的识别精度。
编程与集成
- C#集成:VisionPro 提供与C#的API接口,可以方便地将视觉功能集成到自定义的应用程序中。用户可以通过 CogJobManager 来管理视觉任务,使用 CogToolBlock 来运行和调试视觉工具。
- VPP文件的加载与操作:VisionPro的视觉工具配置可以保存为 .vpp 文件,通过 C# 编程加载这些文件,方便视觉系统的部署和调试。
高级应用
- 多相机配置:VisionPro 支持多相机协同工作,能够从多个角度捕捉图像,应用于复杂的3D场景或全方位检测。
- 视觉检测任务:在实际的工业场景中,VisionPro 可以用于高速生产线的缺陷检测(如划痕、凹坑等),配合合适的光源和相机,可以处理反光、复杂纹理的物体。
视觉项目开发流程
- 从图像采集、预处理、特征提取到缺陷检测的整个流程,VisionPro 都提供了相应的工具。用户可以通过拖拽式的开发环境搭建视觉检测流程,同时也可以在必要时编写脚本或使用API进行高级控制。
外观检测项目流程
- 接到需求
- 选型、客户现场打光
- 客户提供各种类型的不良品 加上部分良品
- 针对缺陷打光、记录打光方式
- 综合不同缺陷的打光方案,看看有的缺陷能不能放在一起
- 前期根据客户提供的样品训练模型
- 模型训练完成后小批量测试产品,同时有人工复判
- 等到模型稳定的时候可以大批量的进行生产(训练模型可以和写程序同步进行,或者说有助理工程师训练模型)
- 写程序、出公司进场调试
检测会涉及到过检或漏检如果漏检但没给你ID,你该怎么做?
例:如果有500片有五片漏检,那可以每片料上面都有一个二维码的,用扫码枪扫一下可以出来ID,读到二维码后,直接复制二维码查找图片,找到这五片的图片
漏检 根据二维码找到产品图拍呢,首先查看图片上有没有缺陷,如果没有缺陷那可能是后续的工站或者作业岗位造成的需要和客户方沟通,如果是我们的软件没有抓取到缺陷,就把改产品图片添加到不良品训练集中重新训练
过检 根据二维码找到产品图片,看下产品图片上是否有缺陷,如果有较小的缺陷,客户认定为良品,我们可以适当优化模型参数,例如降低面积,周长,阈值等的参数,如果没有缺陷可以查看下不良品训练集里有没有错误标注,如果有则优化,如果没有就把当前图片添加到良品训练集中重新训练
设备出现问题处理的流程
- 确认问题点,分析问题原因,解决问题
- 设备能正常运转就让设备先做,在线分析问题
- 设备不能运转就停机解决问题
- 作为视觉工程师,或者视觉售后,如果是视觉问题就确认硬件和视觉算法
- 机构问题机构找售后或机构工程师
- PLC问题就找PLC工程师
怎么调试才算相机清晰
对焦(Focus)调整
- 手动/自动对焦:如果使用的是手动对焦镜头,确保通过调整镜头的对焦环来达到最佳焦点,使目标物体在图像中清晰可见。
- 如果是自动对焦镜头,确认对焦机制工作正常。
- 最大对比度原则:通常,可以通过调整对焦,找到物体边缘对比度最强的点,此时图像的清晰度最高。
分辨率(Resolution)和像素精度
- 相机分辨率:分辨率决定了图像的精细程度,确保选择的相机分辨率能够满足检测要求。例如,如果需要检测非常细微的划痕或凹坑,可能需要高分辨率相机。
- 像素精度:评估物体在图像中的像素大小,确保物体细节不会因分辨率不足而丢失。例如,如果要检测10微米的划痕,图像中至少应有几个像素能够表现这个划痕。
曝光和光源调整
- 曝光时间:调整相机的曝光时间,使得物体表面不过亮也不过暗。曝光过度会导致图像发白,曝光不足则导致图像过暗,影响检测的准确性。
- 光源调整:确保光源均匀且足够亮度,特别是在反光或表面有缺陷的检测中,适当的光源可以大大提升图像清晰度。选择合适的光源类型(如同轴光、漫射光或低角度光)并正确配置角度,以减少反射和提高表面特征的对比度。
图像锐化和去噪
- 锐化过滤:可以通过在软件中应用锐化滤波器,增强图像的边缘,使得表面缺陷更加明显。
- 去噪处理:如果图像中有噪声,可以通过去噪算法(如高斯滤波、中值滤波)减少图像噪声,使得真实的缺陷特征更加突出。
MTF(调制传递函数)测试
- MTF测试:使用调制传递函数(Modulation Transfer Function, MTF)来评估相机系统的分辨能力。这是一种定量分析工具,用于衡量图像系统的清晰度,尤其在高精度场景下,MTF能提供客观指标。
- 测试卡:可以使用标准的测试卡(如USAF 1951)拍摄,检测不同频率的清晰度,确保相机能够分辨目标所需的细节。
对比度调节
- 优化对比度:确保相机的对比度设置适当,使得物体的细节和缺陷能在图像中清晰可见。可以使用对比度直方图来判断图像中的灰度级分布,调整对比度范围使其更适合目标物体的检测。
焦距与视场的匹配
- 镜头选择:确保所选镜头的焦距与相机的视场相匹配,使得目标物体完整地显示在图像中,同时确保细节足够清晰。例如,如果物体较小且需要精确检测,应选择长焦镜头来放大物体细节。
实际检测反馈
- 检测结果反馈:进行缺陷检测时,捕捉到的图像是否能够准确反映缺陷,比如划痕、凹坑和粗糙度等。
- 如果在检测过程中经常出现误检或漏检,可能需要进一步优化图像的清晰度。
漏检的做检测分析报告,会做吗?(FA是异常分析报告)
会,从来料、机构、视觉三方面分析就可以,做完交给上级查看
定位视觉引导常见的场景有哪些
抓取、纠偏、对位贴合
定位视觉引导常见的的标定有哪些?
九点标定、旋转中心标定、上下相机坐标统一
LCD玻璃定位贴合项目
贴合前需要一些准备:
- 对玻璃进行清洁,确保贴合面干净。
- 把相机和光源安装在合适的位置,进行校准与调试。当时用了两个相机:一个相机用于拍摄玻璃的正面,另一个用于拍摄侧面,获取更多的特征信息。
- 然后是三个光源:环形光用于提供均匀的照明,突出边缘的特征;背光源使轮廓更加清晰;条形光用于检测玻璃表面的缺陷。确保检测区域无干扰,光照条件稳定均匀。
- 接着,通过机械手吸取产品移动九个位置,通过相机分别拍照九个位置的图像,获得九组像素坐标。再把像素坐标转换为机械坐标,把九组机械手的坐标对应的视觉坐标填入 Visionpro 的九点标定工具中进行校正,获取标定结果,查看误差值(一般是 5,也就是正负 0.5 精度)。
之后,再通过相机采集工作场景的图像,进行一些预处理(调整图像参数、对比度、亮度、去噪、平滑等处理),识别玻璃的特征、尺寸、位置等信息。再通过标定抓取玻璃的特征标记,旋转三个角度,分析信息,找出旋转中心,计算得出目前玻璃放置的位置是否准确,和标准位置相比有多少的位移差,并反馈当前的 X/Y 坐标值到 PC 控制系统,以确保后面进行准确定位。
之后,将玻璃胶水初步放置在显示屏框架上,通过机械手臂进行粗略定位,通过调整参数精准地贴合到指定位置。贴合过程中确保压力均匀,过大压力可能导致贴合不牢固或玻璃破裂。
贴合后进行检测,是否存在位置偏移、存在气泡。GRR 一般做到 10% 以内。根据评估标准来判断是否符合要求。最后,记录并生成报告。
键盘键帽缺失检测
准备阶段:
- 使用了两个相机:
- 一个远心相机,用于检测对象的成像。
- 一个微距镜头,用于键帽面的表面纹理的检测。
- 使用了两个光源:
- 环形光,用于减少阴影和反光,突出键帽的轮廓和边缘。
- 条形光,用于使键帽表面的特征更明显,有助于更好地提取特征。
- 将相机和光源安装在合适的位置,进行校准与调试。
- 对采集的图像进行去噪预处理,以减少后续的干扰。
- 进行灰度化处理,简化图像,突出键帽的特征。
检测阶段:
- 通过 VP 软件中的模板匹配或特征提取的方式查找键帽的位置。
- 然后使用斑点、对比等工具针对每个键帽,提取能够表示其存在与否的特征(例如面积、形状、灰度值等)。
- 将提取的特征与预设的正常键帽特征进行比较。如果差异超过设定的阈值,则判断为缺失。
- 同时检测键帽表面的字符是否存在划痕或缺失。
结果输出与优化:
- 将检测结果在图像上标记出缺失键帽的位置,以可视化的形式输出。生成相应的报告。之后通过大量的样本测试,进行优化,提高检测的准确率。
- (如果问到准确率、召回率、GRR 是多少、精度等问题,可以根据实际测试数据回答。)
螺母的筛选检测
设备配置与准备:
- 本项目使用了三个相机:
- 一个相机拍摄螺母的表面。一个相机拍摄螺母的底面。一个相机拍摄螺母的侧面。
- 使用了三个光源:
- 环形光用于检测螺母表面。背光源用于检测螺母背面。条形光用于检测螺母侧面。
检测流程:
- 将待检测的螺母放到转盘上。
- 启动转盘,螺母将依次被各个相机拍摄。
- 通过调整相机拍摄的图像,提取能够表示其存在与否的特征(例如面积、形状、灰度值等)。
- 将提取的特征与预设的正常螺母特征进行比较。
结果处理与优化:
- 如果差异超过设定的阈值,则判断为不良品。
- 当不良品通过后续的气泵时,气泵会被触发吹动,将产品吹入不良品盒子中。
- 生成相应的报告。 之后通过大量的样本测试,进行优化,提高检测的准确率。
手机芯片检测
参考链接: https://www.optmv.com/content/details152_4835.html
检测目标: 检测手机芯片表面的脏污、划伤等缺陷。
光源选择:
- 选用球积分光源(例如奥普特的RID系列)。
- 通过降低光源工作距离,使脏污、划伤等缺陷更加明显。
- 球积分光源采用慢反射罩,使光线均匀分布在观察视野中,可以消除表面不平的干扰。
检测思路:
思路一:基于模板对比
- 使用好的芯片作为模板。
- 将待检测芯片与模板芯片进行对比。
- 两张图片相减,得到差异区域。
思路二:基于图像滤波与差分
- 对原始图像进行中值滤波,模糊图像中的缺陷和划痕。
- 将原始图像与中值滤波后的图像进行相减。
- 由于芯片中可能存在白色杂斑和黑色杂斑,且背景可能为黑色或灰白色,因此相减结果需要取绝对值,以获取所有差异。
通用处理步骤(结合上述思路):
- 芯片定位与掩膜:
- 用 PMA (Pattern Matching Algorithm) 工具 框选出芯片位置,找到轮廓。
- 使用掩膜 (Mask) 去除芯片轮廓外的干扰因素(如背景上的脏污、缺陷)。
原点定位:
- 使用 Fixture 工具 进行原点定位。
区域提取:
- 使用仿射变换工具剪切出需要检测的精确区域。
图像预处理:
- 对剪切出的区域进行中值滤波。
差异提取:
- 将预处理前的剪切图与滤波后的图片进行相减,得到差异区域。
缺陷分析:
- 使用 Blob 工具 分析差异区域,提取出芯片表面的缺陷(斑点)。
结果展示:
- 使用 C# 高级脚本 将 Blob 工具筛选出的缺陷区域进行展示。
电池和充电器表面OCR字符检测
参考链接: https://www.china-vision.org/cases-detail/224988.html
OCR手机电池字符缺陷检测
- OCR字符上有白点
- OCR字符模糊
- OCR字符重影
- OCR字符缺失
- OCR字符变形
- 二维码模糊
手机充电器OCR字符残缺检测
- 检测内容: 检测充电器表面镭射的LOGO、标签、配置参数等字体是否存在残缺。
- 检测精度: 0.1mm以内(即检测到残缺线长超过0.05mm或点大小超过0.1mm*0.1mm为不合格产品)。
- OCR字符间距测量
- 测量内容: 产品表面镭射的LOGO、标签、与充电器边沿的距离数据。
- 测量精度: 0.05mm以内。
- 条码读取上传
- 任务: 检测产品表面镭射的条码,上传产品编号和测试结果。
会不会操作VM
会操作vm,自己尝试使用过,对visionpro使用较多,vm和vp的相似程度很高,vp自我感觉更加难,因为页面是英文的,并且属于国外前列的软件,所以对vm可以快速上手
会不会操作PLC
会使用,通过九点标定对机械手进行控制
检测过检、漏检咋办,咋处理,该调啥数
- 漏检:先查看漏检的图片有没有缺陷,没有缺陷说明是后面的工位出现的问题,如果是软件出现的问题,就把漏检的图片,集中起来重新训练
- 过检:如果图片有细小缺陷,客户认为是良品,可以根据实际情况调节面积,周长、阈值等参数
关于串口的建立,需要设置哪些参数
串口通信主要参数:
- 端口名
- 波特率
- 数据位(DataBits)
- 停止位(StopBits)
- 校验位(Parity) 在配置串口时,需要根据实际连接的设备和需求来选择合适的参数。
VP和VM对比的优缺点
VisionPro (VP):
- VisionPro 的界面相对更为复杂,偏向于专业工程师的使用。它更侧重于深度配置和精细调试,因此对于新手或需要快速上手的用户来说,可能有一定的学习曲线。它提供了丰富的工具箱,适合进行复杂的视觉任务。 VisionMaster (VM):
- VisionMaster 的界面相对简洁,更易于使用。它更适合简单的视觉检测任务,或者对于需要快速上手的用户来说更友好。VM 更加注重自动化配置和流程,减少了复杂的调试需求。
运动控制卡
运动控制卡是一种用于控制电机、执行器等运动部件的硬件设备,广泛应用于自动化设备、数控机床、机器人等领域。它通过生成控制信号(如脉冲信号、方向信号等)来精确控制电机的运动,通常用于实现精密的位移、速度控制和轨迹规划。
- 位置控制:控制器通过输出脉冲信号来精确控制电机的转动,从而实现移动部件的精准定位。
- 速度控制:根据设定的参数,可以控制电机以恒定或可变的速度运行,适用于需要平滑加速和减速的场景。
- 插补控制:实现多轴联动控制,使多个轴可以同时进行精确的插补运动,适用于复杂的轨迹规划,如圆弧、直线等。
- 加减速控制:在启动或停止时提供加速度和减速度控制,以确保运动的平稳性。
- 限位和急停:监控运动范围和突发异常情况,触发限位或急停功能以确保安全运行。
- 反馈闭环控制:通过接收编码器等传感器反馈,调整控制信号,形成闭环控制,提高运动的精度和稳定性。
- 品牌:研华、固高科技、雷赛智能、美卡诺
如果现在有10个按钮,我如果要给10个按钮添加不同的功能,有哪些实现方式
- 单独为每个按钮绑定事件处理程序
- 使用单个事件处理程序,通过 Tag 属性区分
- 使用反射或委托
- 动态生成按钮和功能
如何把visionPro要处理的像素尺寸改为实际尺寸,反之如何实现
- 使用标定板: 需要一个具有已知尺寸特征的标定板。标定板上特征点之间的实际物理距离是精确已知的。
- 采集图像: 使用视觉系统(相机+镜头)拍摄标定板的图像。
- 运行标定工具: VisionPro 提供了多种标定工具,例如 CogCalibNPointToNPointTool(用于N点标定)或CogCalibCheckerboardTool(用于棋盘格标定)。
- 在工具中,指定图像中标定板特征点的像素坐标,并输入这些特征点对应的实际物理坐标(例如,毫米)。
- 生成变换: 标定工具会计算出一个变换关系(通常是一个2D变换矩阵),这个变换关系描述了从像素坐标系到物理世界坐标系的映射。
- 应用变换: 标定成功后,这个变换关系就可以被应用到后续的测量中。
当使用测量工具(如 CogDistancePointPointTool)在图像中测量得到一个以像素为单位的距离时,可以将这个像素距离通过标定生成的变换转换为实际的物理距离(如毫米)。VisionPro 的工具通常会自动处理这个转换,前提是它们关联了有效的标定结果(通常通过 Fixture 工具将标定结果传递给后续工具)。
对直方图的了解程度
可以获取一张图像上的最小灰度值,最大灰度值,均值,可以通过灰度值选取某些区域
设备都安装好后,你拿到这个机器接下来你要干什么
- 确认硬件连接是否正确无误(相机,光源,运动控制器,传感器等)
- 检查软件配置,visionpro visionMaster等是否安装正确
- 校准系统,进行相机标定和校准,确定系统能够正确识别到物体的位置和尺寸(九点标定,12点标定)
- 测试环境,调整光源,相机焦距,曝光时间等参数
- 测试运行
这个检测率没有达到要求,你该怎么办
- 分析原因(光源,相机参数调整不对,或者算法设置问题)
- 调整光源和相机参数
- 优化算法
- 提高采集频率或分辨率
如果你做完以上操作,还没有达到要求,你该怎么办
- 与技术团队合作,共同分析原因
- 现场调整设备
- 咨询供应商或者技术支持
如果交付后,客户公司没有操作时没有达到客户要求怎么办
- 培训客户公司操作人员,确保他们能正确操作设备
- 进行远程支持或者现场调试
- 分析操作环境的不同
- 提供改进方案
如果你不能按照规定时间到达客户公司,你该怎么办
- 我的时间安排的很好,不会不能按照规定到达客户公司
- 提前通知客户
- 提供远程支持
- 安排其他工程师到场
如果客户公司要求你必须在这个时间达到,你因为有事会耽误,你该怎么办
- 提前沟通并协调
- 寻求团队的支持
- 紧急情况下提供补偿措施,比如加班加点调试
C#和.net的关系
C# 是一种编程语言,而 .NET 是一个软件开发框架。C# 是 .NET 框架的主要编程语言之一,.NET 提供了运行时环境和类库,使得 C# 程序可以在不同的平台上运行。C# 代码通常被编译成中间语言(IL),然后由 .NET 运行时(CLR)执行。
你用halcon做过的字符识别项目,详细讲述一下(详细流程)。
- 车牌识别
- 蓝色车牌,先对图片进行颜色通道分割,选择出分量适合的通道
- 然后对通道进行阈值分割,将图像进行开运算,将干扰因素消除
- 然后使用连通域解析,将图像分割,使用select_sharp筛选出车牌区域
- 使用变换形状,拿到最小外接矩形,使用fill_up进行填充
- 使用orientation_region拿到图像弧度,使用仿射变换工具进行对原图旋转
- 然后截取车牌区域
- 对图像进行反转,车牌只能识别亮区域
- 使用阈值分割,连通域,将单个字符分割出来
- 使用sort_region对图像进行排序
- 读取识别库
- 给图像中的对象与识别库进行匹配,然后结果
- 进行展示
相机的SDK怎么封装到c#
引入SDK库
- 如果相机SDK是基于C++编写的,则需要使用P/Invoke(Platform Invoke)机制来调用非托管代码。
- 可以使用[DllImport]属性来声明外部方法
创建相机控制类
- 建议将相机SDK的功能封装到一个类中,比如CameraWrapper,这样可以更好地管理相机操作。
定义一些基本的方法,例如OpenCamera、CloseCamera、CaptureImage等,根据SDK的接口实现相应的调用:
封装事件和回调
测试封装结果
VM和C#联合编程
- 配置C#项目并引用VisionMaster的库
- 先创建一个VisionMaster的实例,使用API来连接相机,初始化设备。
- 一旦连接成功,可以通过调用VisionMaster的采集方法来获取图像数据,然后在C#窗体上显示
- 使用VisionMaster的检测功能,如检测边缘、缺陷、形状等。
- 可以通过调用API提供的特征提取、模板匹配等方法,将结果返回到C#,并在界面显示检测结果
VP掌握多少,VM会不会
我对VisionPro较为熟练,掌握了它的图像匹配、缺陷检测、九点标定等功能,并且在多个项目中担任过打光、调试、vpp脚本修改的角色。 VisionMaster方面我具备一定使用经验,能够上手操作
常见的滤波以及其作用
- 均值滤波(Mean Filter):通过计算邻域像素的平均值来平滑图像,减少噪声。
- 中值滤波(Median Filter):通过取邻域像素的中值来去除椒盐噪声,保留边缘信息。
- 高斯滤波(Gaussian Filter):使用高斯函数对图像进行平滑处理,适用于去除高斯噪声。
- 双边滤波(Bilateral Filter):在平滑图像的同时保留边缘信息,适用于去除噪声而不模糊边缘。
- 低通滤波(Low-pass Filter):允许低频信号通过,抑制高频信号,常用于去除图像中的高频噪声。
- 高通滤波(High-pass Filter):允许高频信号通过,抑制低频信号,常用于增强图像的细节和边缘。
- 拉普拉斯滤波(Laplacian Filter):用于边缘检测,通过计算图像的二阶导数来识别边缘和细节。
常见的算子及其作用
- Sobel算子:用于边缘检测,通过计算图像梯度来识别边缘。
- Canny算子:一种多阶段边缘检测算法,能够有效地检测图像中的边缘。
- Laplacian算子:用于检测图像中的二阶导数,能够找到边缘和细节。
- Roberts算子:一种简单的边缘检测算子,通过计算图像的梯度来识别边缘。
- Prewitt算子:类似于Sobel算子,用于边缘检测,通过计算图像梯度来识别边缘。
OCR识别流程,二维码识别流程
- OCR识别流程:
- 图像采集:使用相机或扫描仪获取待识别的文本图像。
- 图像预处理:对图像进行灰度化、二值化、去噪等处理,以提高识别精度。
- 字符分割:将图像中的字符区域进行分割,提取出单个字符。
- 特征提取:对分割出的字符输入对应的文字进行训练。
- 模型识别:使用训练好的OCR模型对提取的特征进行分类,识别出字符。
- 二维码识别流程:
- 图像采集:使用相机或扫描仪获取二维码图像。
- 图像预处理:对图像进行灰度化、二值化等处理,以提高二维码的可读性。
- 二维码定位:使用边缘检测或形状匹配算法定位二维码的位置。
- 创建二维码模型,检测读取图像中的二维码数据代码模型。
- 删除2d数据代码模型释放分配资源。
直方图的原理,傅里叶转换算子,卷积算子
- 直方图:直方图拿到整张图像所有像素点灰度信息,可以得到平均值,最大值,最小值,对灰度进行处理
- 傅里叶变换:傅里叶变换是将时域信号转换为频域信号的数学工具,可以分析图像中的频率成分,常用于图像滤波和特征提取。
- 卷积算子:卷积算子是图像处理中常用的操作,通过将图像与卷积核进行卷积运算,可以实现边缘检测、模糊、锐化等效果。
编码器是什么
是一种用于将物理量(如位置、速度、方向等)转换为可读的电信号或数字信号的设备。 编码器通常分为两种主要类型:增量编码器和绝对编码器。 编码器通常通过光学、磁性或电感原理工作
一个线扫相机扫圆扫出来是个椭圆
- 物体运动速度和相机扫描速度不匹配
- 镜头畸变
- 相机安装角度
- 光源问题,高光反射会使边缘模糊
- 图像处理算法,图像增强,边缘检测参数设置不当
线扫相机基本概念
- 是一种工业相机,专门设计用于捕获高速运动的物体或连续流动的材料的图像。
- 与传统的面阵相机不同,线扫描相机逐行扫描物体,并在一条线上连续捕获图像。
- 主要应用于快速运动物体的高速图像采集,如高速传送带上的产品检测。
普通相机的曝光时间越长取一张图片时间越长吗?
是的
对于多线程任务管理,内存泄露调试,程序Bug调试以及生产过程中的一些异常分析以及排查问题实验的设计与实现
多线程任务管理经验:
- 线程池:使用线程池来管理资源和控制线程数量,确保系统资源不被过度消耗。
- 任务分配:如何将任务合理分配到不同线程上,比如IO密集型和计算密集型任务的分配,避免CPU资源浪费。
- 同步和锁机制:对于需要线程同步的部分,可以讲讲你如何使用锁机制、信号量或并发集合(如ConcurrentQueue等)来管理资源的访问。
内存泄露调试经验:
- 工具使用:比如使用内存分析工具(如Visual Studio自带的诊断工具、WinDbg、DotMemory)找出内存泄露的原因。
- 具体场景:列举一些你排查过的常见内存泄露情况,如事件未解除订阅、未关闭的文件流或数据库连接、未释放的图片资源等。
程序Bug调试经验:
- 断点调试:如何利用断点一步步排查问题。
- 日志记录:讲讲如何通过系统日志或专门的调试日志(如log4net、NLog等)收集数据,定位复杂或偶现问题。
- 异常捕获:讲解异常处理策略,以及如何通过调试和日志结合分析代码的执行路径和状态。
相机的外参和内参分别是什么,如何得到
相机内参(Intrinsic Parameters) 内参是描述相机自身成像特性的参数,主要包括焦距、主点坐标和镜头畸变系数等。内参反映了相机的光学和几何特性,在没有移动相机的位置或调整镜头的情况下,内参一般是固定的。
内参的具体组成:
- 焦距 (f_x, f_y):焦距通常用像素表示,分别是x和y方向的像素单位焦距。
- 主点 (c_x, c_y):相机成像坐标系的原点(即图像中心),通常与传感器的几何中心不完全重合。
- 畸变系数:包括径向畸变(k1, k2, k3 等)和切向畸变(p1, p2 等),主要用于矫正镜头的桶形或枕形畸变。
如何获得相机内参:
- 标定板准备:使用带有已知标记(如棋盘格或圆点阵列)的标定板。
- 拍摄标定图像:将标定板放置在相机视野内,拍摄多张不同角度的标定图像。
- 特征点检测:检测标定板上的特征点(如棋盘格交点或圆点中心)。
- 内参计算:通过标定算法(如张正友标定法)将标定板上的已知物理坐标与图像中的像素坐标进行映射求解,得到焦距、主点位置和畸变系数等内参。
- 在OpenCV等工具中,可以使用函数如 cv2.calibrateCamera() 来完成内参的计算。
相机外参(Extrinsic Parameters) 外参用于描述相机坐标系与世界坐标系之间的关系,主要包括旋转矩阵和平移向量。外参定义了相机在世界坐标系中的位置和朝向,通常表示为从世界坐标系到相机坐标系的转换。
外参的具体组成:
- 旋转矩阵 (R):表示相机坐标系相对于世界坐标系的旋转关系。
- 平移向量 (T):表示相机坐标系相对于世界坐标系的平移关系。
如何获得相机外参:
- 标定板准备:与内参标定相同,使用带有已知位置的标定板。
- 拍摄标定图像:相机对准标定板拍摄,保证标定板在视野内并且有一定角度变化。
- 特征点检测和匹配:检测标定板上的特征点,并匹配已知的标定板坐标(即世界坐标系中的坐标)。
- 外参求解:在已知内参的情况下,使用PnP(Perspective-n-Point)算法求解旋转和平移关系。
- OpenCV 中的 cv2.solvePnP() 可以用于计算外参,前提是已经得到内参,并且可以匹配到3D世界坐标与2D图像坐标。
内参与外参在成像模型中的作用
- s * [u, v, 1]^T = K * [R | T] * [X, Y, Z, 1]^T
- 其中:
- s 是一个比例因子,用于将三维点投影到二维图像平面。
- [u, v] 是图像中的像素坐标。
- [X, Y, Z] 是三维空间中的点的世界坐标。
- K 是内参矩阵,包含焦距和主点坐标。
- R 和 T 是外参矩阵,描述相机相对于世界坐标的旋转和平移。
- s 是比例因子。
内参和外参的应用场景
- 相机校准:获得内参和外参后,可以消除镜头畸变、修正图像。
- 3D重建:利用外参进行多视角图像的融合,实现三维重建。
- 位姿估计:外参描述了相机的空间位置和姿态,可以在机器人导航、增强现实等场景中使用。
- 精确测量:已知内外参数,可以实现高精度的尺寸测量和物体定位。
点云数据格式有哪些,如果要做点云拼接有哪些常见方法
点云数据格式常见的有:
- PCD(Point Cloud Data):由PCL(Point Cloud Library)定义的点云数据格式,常用于存储和处理点云数据。
- PLY(Polygon File Format):一种常见的点云数据格式,支持存储点的颜色、法线等属性。
- OBJ(Wavefront Object):虽然主要用于3D模型,但也可以存储点云数据。
- LAS/LAZ:用于地理信息系统(GIS)中的点云数据格式,常用于激光雷达数据。 点云拼接常见方法:
- ICP(Iterative Closest Point):一种迭代算法,通过最小化点云之间的距离来对齐点云。
- NDT(Normal Distributions Transform):通过将点云转换为概率分布来进行对齐,适用于大规模点云数据。
如果想实现2D相机测量一已知尺寸标定板相对位置常见的测量方法有哪些;
常见的测量方法有:
- 直接测量:使用相机拍摄标定板,提取特征点(如角点或圆心),然后计算这些特征点在图像中的像素坐标与实际物理坐标之间的关系。
- 标定算法:使用标定算法(如张正友标定法)来计算相机的内参和外参,从而将像素坐标转换为实际物理坐标。
使用两个相机拍摄较大物体局部并进行标定和位置角度纠偏的过程:
- 相机标定
- 单相机标定:分别对两个相机单独进行标定。通常采用棋盘格标定板,拍摄不同角度和位置的棋盘格图像。利用棋盘格的已知角点坐标(世界坐标)和检测到的图像角点坐标,通过张正友标定法等方法来计算相机的内参数(包括焦距、主点坐标等)和外参数(相机相对于标定板的旋转和平移)。
- 双相机相对标定:在完成单相机标定后,需要确定两个相机之间的相对位置和姿态关系,即外参数。这可以通过同时观察一个已知的三维物体(如带有标记点的特制标定物)来实现。通过在两个相机图像中提取对应的特征点,然后利用三角测量原理和非线性优化算法(如Bundle Adjustment)计算出两个相机之间的旋转矩阵和平移向量。
- 位置角度纠偏
- 特征提取与匹配:在两个相机拍摄的局部物体图像中提取特征点,如SIFT、SURF或ORB等特征点。然后通过特征匹配算法找到两幅图像中对应的特征点对。
- 计算变换关系:根据匹配的特征点对,使用最小二乘法等方法计算从一个相机图像到另一个相机图像的变换矩阵(包括旋转和平移)。假设在相机1图像中有一点,通过变换矩阵可以将其映射到相机2图像中的对应点,即,其中是一个的矩阵,包含了旋转、平移、缩放等信息。
- 位置角度纠偏:利用计算得到的变换矩阵对物体局部在两个相机图像中的位置和角度进行纠偏。例如,如果想要将相机1中的局部物体位置和角度与相机2中的对齐,可以将相机1中的点通过变换矩阵变换到相机2的坐标系下,从而实现位置和角度的统一。在实际操作中,对于每个要纠偏的点或物体轮廓上的点,都按照上述矩阵乘法进行计算,然后根据纠偏后的点重新构建物体在统一坐标系下的局部表示。
在整个过程中,矩阵变换起到了关键作用。通过相机标定得到的内参数矩阵和外参数矩阵,可以将三维世界坐标转换为相机图像坐标。在双相机系统中,两个相机之间的相对旋转和平移矩阵用于将一个相机坐标系下的点转换到另一个相机坐标系下,从而实现位置和角度的纠偏。
畸变的类型
- 径向畸变
- 枕形畸变
- 桶形畸变
- 透视畸变