awolfbee 发表于 2020-12-26 21:07:36



侧面拍摄的图片应该如上图所示。如何识别A点在左边还是在右边,这应该是关键。

机械部分的设计,因识别方向不同,全部作废。看来停下机械部分的设计是正确的,应当先将最关键的部分,也就是识别部分搞定之后才能针对识别的位置和方向设计机械部分。本末不可倒置。

大白小白 发表于 2020-12-26 21:15:19

awolfbee 发表于 2020-12-22 20:25
最近在找工作,面试比较忙,天气也比较冷,冷人就开始犯懒,不想动了……惰性啊!

大侠怎么又在找工作?开了老板?

awolfbee 发表于 2021-1-2 09:20:48

#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <stdlib.h>
#include <stdio.h>
#include <opencv2/highgui/highgui_c.h>
#include <math.h>
//#include "iostream"
//#include "cv.h"
//#include "highgui.h"
//#include "math.h"
using namespace cv;//命名空间CV
using namespace std;//命名空间 std

int threshold_value = 225;//启动程序时的阈值初始值,因为227能够完全提取轮廓,所以设置为225,实际上227也可以。
int threshold_type = 3;   //启动程序的时候阈值类型,默认的为不足部分取零
int const max_value = 255;
int const max_type = 4;
int const max_BINARY_value = 255;

    CvFont font;
    uchar* ptr;
    char label;
    char label2;

Mat src, blured, src_e, src_gray, dst; //类定义几个图片变量,dst是最后转化阈值之后的图片,src.gray是灰度图
                                                //在C语言中“char*”是声明一个字符类型du的指针,定义数据类型,char可以定义字符zhi有变量、数组、指针。dao
                                                //例如:char *string="I love C#!"
                                                //定义了一个字符指针变量string,用字符串常量"I love C#!",对它进行初始化。对字符指针变量初始化,实际上就是把字符串第1个元素的地址(即存放字符串的字符数组的首元素地址)赋给string。*/
Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蚀的参数
char* window_name = "阈值演示程序20201121";
char* trackbar_type = "类型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted";//
char* trackbar_value = "数值";

/// 自定义函数声明
void Threshold_Demo( int, void* );

/**
* @主函数
*/
int main( int argc, char** argv )
{
/// 读取一副图片,不改变图片本身的颜色类型(该读取方式为DOS运行模式)
src = imread("121.JPG", 1); //目前还未使用摄像头拍摄照片,暂时以直接读取文件的方式来测试。
erode (src, src_e, element); //对图片进行腐蚀,参数可调,正常为9或者10,过大则造成轮廓过小,应该再进行降噪
blur (src_e, blured, Size (3,3));//3*3内核降噪
imshow("腐蚀和降噪后的图片", blured);//显示图片
        int width=blured.rows;//图像的行列
        int height=blured.cols;//图像的列数量
        cout<<width<<endl;    //显示行列的具体像素
        cout<<height<<endl;
        int a; //定义整型数组,后面的1应该可以不要的
        int b;//设置一维数组,用于判断曲线的切线斜率

/// 将图片转换成灰度图片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图,            下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
cvtColor( blured, src_gray, CV_RGB2GRAY );

/// 创建一个窗口显示图片
namedWindow( window_name, CV_WINDOW_AUTOSIZE );

/// 创建滑动条来控制阈值
createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);

createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);

/// 初始化自定义的阈值函数
Threshold_Demo( 0, 0 );

// Mat img=src;//暂时无用
//imshow("转化之后图片",dst);

                                                        //遍历图片的每个像素点,当像素点的阈值大于227时,将最左侧的该像素地址保存在二维数组中,在该行之后的像素点抛弃,如果阈值低于227,则向下遍历至该行末,然后从下一行开始对像素进行比较
       
//Mat BW = imread(imgName);
//int value = BW.at<uchar>(191, 51);
   int width1=dst.rows;//处理之后图像的行列
       int height1=dst.cols;//处理之后图像的列数量

        for (int i=0 ; i<height1; i++)//从第一行开始应该从最后一行开始向上检索,这样可以减少计算量,一旦出现与之前曲线K值相反的方向,则确定是拐点,不用再考虑,但是要考虑出现切线斜率始终是减少的趋势,这种情况下往往是蒜尖
        {
               for (int j = 0; j < width1; j++) //从第一行的第一列开始
                {
               //int index = i * width + j;
               int value = dst.at<uchar>(i,j); //读取给定坐标处的像素值
                //if; //像素值
               //int data = (int)dst.data;
                                if ( value >200) //如果像素值大于某个数值,则将其地址记录在数组内,且仅记录首像素,后面的舍弃
                                                        {       
                                                        a=j; //数组值等于列数,便于后期对比
                                                        //cout<<i<<" --- "<<j<<endl; //i为行数
                                                        //cout<<i<<" -坐标-- "<<a<<endl;
                                                        if (i>1)
                                                                {//11
                                                                        if (a<a)//如果第一行中大于某个阈值的像素地址与下一行相比靠右,也就是列数比上一行要大,则说明该曲线向左侧倾斜,说
                                                                                                    //明是底部,如果曲线向右侧弯曲,则是蒜尖 (之所以用i-1,是因为总不能和没有像素的地址对比,所以必须向后取值)
                                                                        {
                                                                        b=0;             //因此,当下一行的地址比上一行的地址小,则用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。
                                                                        }
                                                                        else if (a>=a)   
                                                                        {
                                                                        b=1;
                                                                        }

                                                        cout<<i<<" -标识符-- "<<b<<endl;       
                                            //cout<<j<<endl; //j为列数
                                                                } //11
                                                       

                         break;
                                        }
                                                        }
               }
        //开始对b数组进行分析,确定是否为头尾(但是需要对曲线进行圆滑处理)
        for (int i=0 ; i<height1; i++)//对数组b进行遍历,检查是否存在误判的问题
                                                                        //寻找拐点,找到用于判断的后段曲线的拐点
                                                                        //对图形进行圆滑处理,除了最大的拐点之外,尽量不要出现折线
       
       
       
   // int width=dst.rows;//图像的行列
        //int height=dst.cols;//图像的列数量
        cout<<width<<endl;    //显示行列的具体像素
        cout<<height<<endl;
        //for (int i =height1-5 ; i>20; i--) //对收集的坐标数据进行分析
               
// 等待用户按键。如果是ESC健则退出等待过程。
while (true)
{
    int c;
    c = waitKey( 20 );
    if( (char)c == 27 )
      { break; }
   }

}


/**
* @自定义的阈值函数
*/
void Threshold_Demo( int, void* )
{
/* 0: 二进制阈值
   1: 反二进制阈值
   2: 截断阈值
   3: 0阈值
   4: 反0阈值
   */

threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );

imshow( window_name, dst );
}





/*
void main()
{
               
        //读入彩色图像 单通道图像(CV_8UC1);CV 8位未指定的1通道的图像,backImg是单通道灰色图
       
    //Mat img = imread("fruits.jpg");
        Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图,            下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
    imshow("灰度图", img);
        //确定图像的尺寸,行列,
        int width=img.rows;   //图片的变量名加上行列,就是行列的数据
        int height=img.cols;
        cout << width << endl;   //显示行列的数据本图片已经用358的像素值裁剪了,所以形成的就是高宽都是358
        cout << height << endl;
    //定义一个二维数组,a,其行数等于图像行数,列数就一列,用于记录图片上像素的亮度超过某个阈值的像素所在的列数,用于下一步的对比。
        int a;   //确定一个358的二维数组

//int height = backImg.rows;   //backImg是图片变量名
//int width = backImg.cols;
for (int i = 0; i < height; i++)
{
               for (int j = 0; j < width; j++)
       {
               int index = i * width + j;
                //像素值
               int data = (int)img.data;
       }
}
        waitKey();
}
*/

awolfbee 发表于 2021-1-2 09:23:11

以上为使用OPENCV作为视觉识别的工具,目前测试的方式是以一道激光照射在蒜瓣上,根据激光产生的亮条的形状以及拐点判断蒜瓣的头尾,对于清理非常干净的蒜瓣来说,这样识别问题不是很大,基本上还是可以判断的,但是对于没有清理干净的蒜瓣,例如底部还有残留的块状根部,或者是还有蒜皮,这样就会对识别产生干扰,因此需要使用更复杂的算法排除干扰。

awolfbee 发表于 2021-1-2 09:24:55

目前仅用保存在电脑中的图片进行测试,暂时还没有使用摄像头连续拍照,关于如何排序,还得等识别没有问题之后再说。


元旦放几天假,总算有点时间研究下。

大白小白 发表于 2021-1-4 13:02:56

awolfbee 发表于 2021-1-2 09:20
#include
#include
#include


lzv5,不明觉厉!

这个需要安装opencv的什么软件,什么版本,

才能在C环境下编译测试?

awolfbee 发表于 2021-1-22 22:26:06



用一次性筷子做了个简易的相机支架,第一次居然做低了,不能拍摄大蒜的全貌,然后在上面增加了一个小的支架,双杠上再增加双杠。



拍摄的大蒜图片,背景色应该为黑色的比较好,还有就是光源没选择好,要在支架上再增加LED照明灯,设置好光源才行。搞视觉,的确麻烦。

相机的像素选择有点低,不过28元的摄像头,还能指望个啥,能拍摄照片就不错了。

awolfbee 发表于 2021-1-22 22:35:32

03年购买了一个飞利浦的剃须刀,用了几年后电池弹片上锈不能用了,于是就用锂电池装上,之前用的是一个巨大的翘板开关,而且是用不干胶带缠绕的,虽然实用,但是很难看。今天把剃须刀带到公司去,整理了下,还安装了一块锂电池充电板,焊接完毕后再用热熔胶固定下相对位置,把电池的触点用胶保护起来,这样就比较完美了。充电时是红色灯,充满了就转绿色灯。
实际上我有好几个剃须刀,但是就这个用的比较顺手点,所以就没舍得丢。到现在已经用了18年了,刀片在玻璃板上磨过几次,依然非常锋利。




孙启明 发表于 2021-1-24 11:34:26

awolfbee 发表于 2021-1-22 22:26
用一次性筷子做了个简易的相机支架,第一次居然做低了,不能拍摄大蒜的全貌,然后在上面增加了一个小的 ...

残存块根的蒜瓣,从形状上不好识别,可以从色差上面进行识别。

awolfbee 发表于 2021-1-31 22:09:17

用未解锁的手机屏幕作为背景,效果非常好。调节了下焦距,基本上能分辨出外观来。

先用带皮蒜瓣,然后剥了几个蒜瓣,写了一段程序,现在能够使用程序读取照片了。

准备搞一个黑色的绒布再加上玻璃板作为背景,然后要粘贴上定位条,这样每个蒜瓣的原点就确定了,便于后期的程序书写。



页: 5 6 7 8 9 10 11 12 13 14 [15] 16 17 18 19 20 21 22 23 24
查看完整版本: 开始设计一种大蒜播种机