运用AI翻译漫画(二)

构建代码

构建这个PC桌面应用,我们需要几个步骤:

在得到第一次的显示结果后,经过测试,有很大可能会根据结果再对界面进行调整,实际上也是一个局部的软件工程中的迭代开发。

界面设计

启动Visual Studio 2017, 创建一个基于C#语言的WPF(Windows Presentation Foundation)项目:

WPF是一个非常成熟的技术,在有界面展示和交互的情况下,使用XAML设计/渲染引擎,比WinForm程序要强101倍,再加上有C#语言利器的帮助,是写PC桌面前端应用的最佳组合。

给Project起个名字,比如叫“CartoonTranslate”,选择最新的.NET Framework (4.6以上),然后点击”OK”。我们先一起来设计一下界面:

Input URL:用于输入互联网上的一张漫画图片的URL

Engine:指的是两个不同的算法引擎,其中,OCR旧引擎可以支持25种语言,识别效果可以接受;而Recognize Text新引擎目前只能支持英文,但效果比较好。

Language:制定当前要翻译的漫画的语言,我们只以英文和日文为例,其它国家的漫画相对较少,但一通百通,一样可以支持。

右侧的一堆Button了解一下:

Show:展示Input URL中的图片到下面的图片区

OCR:调用OCR服务

Translate:调用文本翻译服务,将日文或者英文翻译成中文

下侧大面积的图片区了解一下:

Source Image:原始漫画图片

Target Image:翻译成中文对白后的漫画图片

界面设计代码

我们在MainWindow.xaml文件里面填好以下code:

<Window x:Class="CartoonTranslate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CartoonTranslate"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Grid.Row="0">
            <TextBlock Grid.Row="0" Text="Input URL:"/>
            <TextBox x:Name="tb_Url" Grid.Row="1" Width="600"
                     Text="http://stat.ameba.jp/user_images/20121222/18/secretcube/2e/19/j/o0800112012341269548.jpg"/>
            <Button x:Name="btn_Show" Content="Show" Click="btn_Show_Click" Width="100"/>
            <Button x:Name="btn_OCR" Content="OCR" Click="btn_OCR_Click" Width="100"/>
            <Button x:Name="btn_Translate" Content="Translate" Click="btn_Translate_Click" Width="100"/>
        </StackPanel>
        <StackPanel Grid.Row="1" Orientation="Horizontal">
            <TextBlock Text="Engine:"/>
            <RadioButton x:Name="rb_V1" GroupName="gn_Engine" Content="OCR" Margin="20,0" IsChecked="True" Click="rb_V1_Click"/>
            <RadioButton x:Name="rb_V2" GroupName="gn_Engine" Content="Recognize Text" Click="rb_V2_Click"/>
            <TextBlock Text="Language:" Margin="20,0"/>
            <RadioButton x:Name="rb_English" GroupName="gn_Language" Content="English"/>
            <RadioButton x:Name="rb_Japanese" GroupName="gn_Language" Content="Japanese" IsChecked="True" Margin="20,0"/>
        </StackPanel>
        <Grid Grid.Row="3">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="40"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="Source Image" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            <TextBlock Grid.Column="2" Text="Target Image" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            <Image x:Name="imgSource" Grid.Column="0" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
            <Image x:Name="imgTarget" Grid.Column="2" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
            <Canvas x:Name="canvas_1" Grid.Column="0"/>
            <Canvas x:Name="canvas_2" Grid.Column="2"/>
        </Grid>
</Grid>
</Window>

处理事件

关于XAML语法的问题不在本文的讨论范围之内。上面的XAML写好后,编译时会出错,因为里面定义了很多事件,在C#文件中还没有实现。所以,我们现在把事件代码补上。

局部变量定义(在MainWindow.xaml.cs的MainWindow class里面):

// using “OCR” or “Recognize Text”
private string Engine;
// source language, English or Japanese
private string Language;
// OCR result object
private OcrResult.Rootobject ocrResult;

按钮”Show”的事件

点击Show按钮的事件,把URL中的漫画的地址所指向的图片加载到窗口中显示:

private void btn_Show_Click(object sender, RoutedEventArgs e)
{
    if (!Uri.IsWellFormedUriString(this.tb_Url.Text, UriKind.Absolute))
    {
        // show warning message
        return;
    }
    // show image at imgSource
    BitmapImage bi = new BitmapImage();
    bi.BeginInit();
    bi.UriSource = new Uri(this.tb_Url.Text);
    bi.EndInit();
    this.imgSource.Source = bi;
    this.imgTarget.Source = bi;
}

在上面的代码中,同时给左右两个图片区域赋值,显示两张一样的图片。

按钮”OCR”的事件

点击OCR按钮的事件,会调用OCR REST API,然后根据返回结果把所有识别出来的文字用红色的矩形框标记上:

private async void btn_OCR_Click(object sender, RoutedEventArgs e)
{
    this.Engine = GetEngine();
    this.Language = GetLanguage();
    if (Engine == "OCR")
    {
        ocrResult = await CognitiveServiceAgent.DoOCR(this.tb_Url.Text, Language);
        foreach (OcrResult.Region region in ocrResult.regions)
        {
            foreach (OcrResult.Line line in region.lines)
            {
                if (line.Convert())
                {
                    Rectangle rect = new Rectangle()
                    {
                        Margin = new Thickness(line.BB[0], line.BB[1], 0, 0),
                        Width = line.BB[2],
                        Height = line.BB[3],
                        Stroke = Brushes.Red,
                        //Fill =Brushes.White
                    };
                    this.canvas_1.Children.Add(rect);
                }
            }
        }
    }
    else
    {
    }
}

在上面的代码中,通过调用DoOCR()自定义函数返回了反序列化好的类,再依次把返回结果集中的每个矩形生成一个Rectangle图形类,它的left和top用Margin的方式来定义,width和height直接赋值即可,把这些Rectangle图形类的实例添加到canvas_1的Visual Tree里即可显示出来(这个就是WPF的好处啦,不用处理绘图事件,但性能不如用Graphics类直接绘图)。

按钮”Translate”的事件

点击Translate按钮的事件:

private async void btn_Translate_Click(object sender, RoutedEventArgs e)
{
    List<string> listTarget = await this.Translate();
    this.ShowTargetText(listTarget);
}
​
private async Task<List<string>> Translate()
{
    List<string> listSource = new List<string>();
    List<string> listTarget = new List<string>();
    if (this.Version == "OCR")
    {
        foreach (OcrResult.Region region in ocrResult.regions)
        {
            foreach (OcrResult.Line line in region.lines)
            {
                listSource.Add(line.TEXT);
                if (listSource.Count >= 25)
                {
                    List<string> listOutput = await CognitiveServiceAgent.DoTranslate(listSource, Language, "zh-Hans");
                    listTarget.AddRange(listOutput);
                    listSource.Clear();
                }
            }
        }
        if (listSource.Count > 0)
        {
            List<string> listOutput = await CognitiveServiceAgent.DoTranslate(listSource, Language, "zh-Hans");
            listTarget.AddRange(listOutput);
        }
    }
    return listTarget;
}
private void ShowTargetText(List<string> listTarget)
{
    int i = 0;
    foreach (OcrResult.Region region in ocrResult.regions)
    {
        foreach (OcrResult.Line line in region.lines)
        {
            string translatedLine = listTarget[i];
            Rectangle rect = new Rectangle()
            {
                Margin = new Thickness(line.BB[0], line.BB[1], 0, 0),
                Width = line.BB[2],
                Height = line.BB[3],
                Stroke = null,
                Fill =Brushes.White
            };
            this.canvas_2.Children.Add(rect);
            TextBlock tb = new TextBlock()
            {
                Margin = new Thickness(line.BB[0], line.BB[1], 0, 0),
                Height = line.BB[3],
                Width = line.BB[2],
                Text = translatedLine,
                FontSize = 16,
                TextWrapping = TextWrapping.Wrap,
                Foreground = Brushes.Red
            };
            this.canvas_2.Children.Add(tb);
            i++;
        }
    }
}

上面这段代码中,包含了两个函数:this.Translate()和this.ShowTargetText()。

我们先看第一个函数:最难理解的地方可能是有个“25“数字,这是因为Translate API允许一次提交多个字符串并一起返回结果,这样比你提交25次字符串要快的多。翻译好的结果按顺序放在listOutput里,供后面使用。

再看第二个函数:先根据原始文字的矩形区域,生成一些白色的实心矩形,把它们贴在右侧的目标图片上,达到把原始文字覆盖(扣去)的目的。然后再根据每个原始矩形生成一个TextBlock,设定好它的位置和尺寸,再设置好翻译后的结果(translatedLine),这样就可以把中文文字贴到图上了。

选项按钮的事件

点击Radio Button的事件:

private void rb_V1_Click(object sender, RoutedEventArgs e)
{
    this.rb_Japanese.IsEnabled = true;
}
private void rb_V2_Click(object sender, RoutedEventArgs e)
{
    this.rb_English.IsChecked = true;
    this.rb_Japanese.IsChecked = false;
    this.rb_Japanese.IsEnabled = false;
}
private string GetLanguage()
{
    if (this.rb_English.IsChecked == true)
    {
        return "en";
    }
    else
    {
        return "ja";
    }
}
private string GetEngine()
{
    if (this.rb_V1.IsChecked == true)
    {
        return "OCR";
    }
    else
    {
        return "RecText";
    }
}

API数据访问部分

我们需要在CatroonTranslate工程中添加以下三个.cs文件:

  • CognitiveServiceAgent.cs

  • OcrResult.cs

  • TranslateResult.cs

与认知服务交互

CognitiveServiceAgent.cs文件完成与REST API交互的工作,包括调用OCR服务的和调用翻译服务的代码:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;
​
namespace CartoonTranslate
{
    class CognitiveServiceAgent
    {
        const string OcrEndPointV1 = "https://westcentralus.api.cognitive.microsoft.com/vision/v2.0/ocr?detectOrientation=true&language=";
        const string OcrEndPointV2 = "https://westcentralus.api.cognitive.microsoft.com/vision/v2.0/recognizeText?mode=Printed";
        const string VisionKey1 = "4c20ac56e1e7459a05e1497270022b";
        const string VisionKey2 = "97992f0987e4be6b5be132309b8e57";
        const string UrlContentTemplate = "{{\"url\":\"{0}\"}}";
​
        const string TranslateEndPoint = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&from={0}&to={1}";
        const string TKey1 = "04023df3a4c499b1fc82510b48826c";
        const string TKey2 = "9f76381748549cb503dae4a0d80a80";
​
        public static async Task<List<string>> DoTranslate(List<string> text, string fromLanguage, string toLanguage)
        {
            try
            {
                using (HttpClient hc = new HttpClient())
                {
                    hc.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", TKey1);
                    string jsonBody = CreateJsonBodyElement(text);
                    StringContent content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
                    string uri = string.Format(TranslateEndPoint, fromLanguage, toLanguage);
                    HttpResponseMessage resp = await hc.PostAsync(uri, content);
                    string json = await resp.Content.ReadAsStringAsync();
                    var ro = Newtonsoft.Json.JsonConvert.DeserializeObject<List<TranslateResult.Class1>>(json);
                    List<string> list = new List<string>();
                    foreach(TranslateResult.Class1 c in ro)
                    {
                        list.Add(c.translations[0].text);
                    }
                    return list;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return null;
            }
        }
​
        private static string CreateJsonBodyElement(List<string> text)
        {
            var a = text.Select(t => new { Text = t }).ToList();
            var b = JsonConvert.SerializeObject(a);
            return b;
        }
​
        /// <summary>
        /// 
        /// </summary>
        /// <param name="imageUrl"></param>
        /// <param name="language">en, ja, zh</param>
        /// <returns></returns>
        public static async Task<OcrResult.Rootobject> DoOCR(string imageUrl, string language)
        {
            try
            {
                using (HttpClient hc = new HttpClient())
                {
                    ByteArrayContent content = CreateHeader(hc, imageUrl);
                    var uri = OcrEndPointV1 + language;
                    HttpResponseMessage resp = await hc.PostAsync(uri, content);
                    string result = string.Empty;
                    if (resp.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        string json = await resp.Content.ReadAsStringAsync();
                        Debug.WriteLine(json);
                        OcrResult.Rootobject ro = Newtonsoft.Json.JsonConvert.DeserializeObject<OcrResult.Rootobject>(json);
                        return ro;
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                Debug.Write(ex.Message);
                return null;
            }
        }
​
        private static ByteArrayContent CreateHeader(HttpClient hc, string imageUrl)
        {
            hc.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", VisionKey1);
            string body = string.Format(UrlContentTemplate, imageUrl);
            byte[] byteData = Encoding.UTF8.GetBytes(body);
            var content = new ByteArrayContent(byteData);
            content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            return content;
        }
    }
}

其中,DoTranslate()函数和DoOCR()函数都是HTTP调用,很容易理解。只有CreateJsonBodyElement函数需要解释一下。前面提到过我们一次允许给服务器提交25个字符串做批量翻译,因此传进来的是个List<string>,经过这个函数的简单处理,会得到以下JSON格式的数据作为HTTP的Body:

// JSON Data as Body
[
        {“Text” : ”第1个字符串”},
        {“Text” : ”第2个字符串”},
        ……..
        {“Text” : ”第25个字符串”},
]

OCR服务的数据类定义

OcrResult.cs文件是OCR服务返回的JSON数据所对应的类,用于反序列化:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
​
namespace CartoonTranslate.OcrResult
{
    public class Rootobject
    {
        public string language { get; set; }
        public string orientation { get; set; }
        public float textAngle { get; set; }
        public Region[] regions { get; set; }
    }
​
    public class Region
    {
        public string boundingBox { get; set; }
        public Line[] lines { get; set; }
    }
​
    public class Line
    {
        public string boundingBox { get; set; }
        public Word[] words { get; set; }
​
        public int[] BB { get; set; }
        public string TEXT { get; set; }
​
​
        public bool Convert()
        {
            CombineWordToSentence();
            return ConvertBBFromString2Int();
        }
​
        private bool ConvertBBFromString2Int()
        {
            string[] tmp = boundingBox.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (tmp.Length == 4)
            {
                BB = new int[4];
                for (int i = 0; i < 4; i++)
                {
                    int.TryParse(tmp[i], out BB[i]);
                }
                return true;
            }
            return false;
        }
​
        private void CombineWordToSentence()
        {
            StringBuilder sb = new StringBuilder();
            foreach (Word word in words)
            {
                sb.Append(word.text);
            }
            this.TEXT = sb.ToString();
        }
​
    }
​
    public class Word
    {
        public string boundingBox { get; set; }
        public string text { get; set; }
    }
}

需要说明的是,服务器返回的boundingBox是个string类型,在后面使用起来不太方便,需要把它转换成整数,所以增加了CovertBBFromString2Int()函数。还有就是返回的是一个个的词(Word),而不是一句话,所以增加了CombineWordToSentence()来把词连成句子。

翻译服务的数据类定义

TranslateResult.cs文件翻译服务返回的JSON所对应的类,用于反序列化:

namespace CartoonTranslate.TranslateResult
{
    public class Class1
    {
        public Translation[] translations { get; set; }
    }
​
    public class Translation
    {
        public string text { get; set; }
        public string to { get; set; }
    }
}

小提示:在VS2017中,这种类不需要手工键入,可以在Debug模式下先把返回的JSON拷贝下来,然后新建一个.cs文件,在里面用Paste Special从JSON直接生成类就可以了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/304018.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构与算法 - 线性表

文章目录 第1关&#xff1a;实现一个顺序存储的线性表第2关&#xff1a;实现一个链接存储的线性表 第1关&#xff1a;实现一个顺序存储的线性表 编程要求 本关任务是实现 step1/Seqlist.cpp 中的SL_InsAt、SL_DelAt和SL_DelValue三个操作函数&#xff0c;以实现线性表中数据的…

[答疑]领域特定语言DSL属于伪创新吗(谷爱凌)

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 Zeyu 2024-1-4 9:20 马丁福勒的领域特定语言DSL是否有阅读的价值&#xff1f;属于伪创新吗&#xff1f; UMLChina潘加宇 这个问题就有点伪创新 &#xff0c;让人误以为DSL是Fowler发…

本地部署Canal笔记-实现MySQL与ElasticSearch7数据同步

背景 本地搭建canal实现mysql数据到es的简单的数据同步&#xff0c;仅供学习参考 建议首先熟悉一下canal同步方式&#xff1a;https://github.com/alibaba/canal/wiki 前提条件 本地搭建MySQL数据库本地搭建ElasticSearch本地搭建canal-server本地搭建canal-adapter 操作步骤…

shp与数据库(插入数据)

前言 正文 geopandas与shp文件创建表和录入数据 解释一下上面的代码 查询cd2表的geometry字段 查看一下表 前一篇博客的冲突 问题的解决 POLYGON与MUTLIPOLYGON的说明 解决问题的代码 修改表的创建 shapefile和sqlalchemy插入数据 数据库查询 最后 前言 前一篇讲解…

与AI合作 -- 写一个modern c++单例工厂

目录 前言 提问 bard给出的答案 AI答案的问题 要求bard改进 人类智能 AI VS 人类 前言 通过本文读者可以学到modern C单例模式工厂模式的混合体&#xff0c;同时也能看到&#xff1a;如今AI发展到了怎样的智能程度&#xff1f;怎样让AI帮助我们快速完成实现头脑中的想法&…

【hcie-cloud】【17】华为云Stack灾备服务介绍【灾备方案概述、备份解决方案介绍】【上】

文章目录 前言灾备方案概述灾备的定义灾备的重要性故障和灾难对业务连续性带来的挑战灾备系统的衡量指标RTO与RPO分析 灾备等级标准数据中心容灾解决方案全景图云灾备服务总结架构华为云Stack灾备服务总览 备份解决方案介绍云备份服务介绍备份服务架构介绍云备份服务组件功能介…

界面原型设计工具有哪些?看看这9个

界面原型设计是现代设计师必备的技能之一。在设计数字产品或应用程序时&#xff0c;界面原型是将概念转化为具体可交互界面的重要步骤。对于新手小白来说&#xff0c;选择一款易于上手且功能强大的界面原型设计工具至关重要。本文将介绍 9 个常用的界面原型设计工具&#xff0c…

计算机体系结构动态调度(计分板及Tomasulo)学习记录

1.动态调度核心思想&#xff1a;允许就绪指令越过前方停顿指令&#xff0c;提前进入运行&#xff08;乱序执行&#xff09; 就绪指令指不存在资源冲突、操作数已就绪的指令&#xff0c;例如&#xff0c;计分板算法使用计分板来实现&#xff0c;Tomasulo使用保留站来实现&#…

苹果电脑交互式原型设计软件Axure RP 9 mac特色介绍

Axure RP 9 for Mac是一款交互式原型设计软件&#xff0c;使用axure rp9以最佳的方式展示您的作品&#xff0c;优化现代浏览器并为现代工作流程设计。同时确保您的解决方案正确完整地构建。Axure RP 9 for Mac为您整理笔记&#xff0c;将其分配给UI元素&#xff0c;并合并屏幕注…

swing快速入门(三十九)进度对话框

&#x1f381;注释很详细&#xff0c;直接上代码 上一篇 &#x1f9e7;新增内容 &#x1f9e8;1.模拟耗时操作 &#x1f9e8;2.使用计时器更新进度对话框 &#x1f380;源码&#xff1a; package swing31_40;import javax.swing.*; import java.awt.event.ActionEvent; import …

【debug】为什么ansible中使用command出错

碎碎念 在使用ansible执行command的时候&#xff0c;遇到执行会出错的command 比如执行source打算读取环境变量的时候 错误提示为&#xff1a; 没有那个文件或目录:source 一开始以为是错误提示有问题&#xff0c;一直在testrc的路径上检查&#xff0c;但是同样一行命令使用…

C++八股学习心得.8

1.const知道吗&#xff1f;解释其作用 const 修饰类的成员变量&#xff0c;表示成员常量&#xff0c;不能被修改。 const修饰函数承诺在本函数内部不会修改类内的数据成员&#xff0c;不会调用其它非 const 成员函数。 如果 const 构成函数重载&#xff0c;const 对象只能调…

聊聊 Java 集合框架中的 ArrayList

其实 Java 集合框架也叫做容器&#xff0c;主要由两大接口派生而来&#xff0c;一个是 collection,主要存放对象的集合。另外一个是Map, 存储着键值对&#xff08;两个对象&#xff09;的映射表。 下面就来说说 List接口&#xff0c;List存储的元素是有序、可重复的。其下有三个…

配置git服务器

第一步&#xff1a; jdk环境配置 &#xff08;1&#xff09;搜索【高级系统设置】&#xff0c;选择【高级】选项卡&#xff0c;点【环境变量】 &#xff08;2&#xff09;在【系统变量】里面&#xff0c;点击【新建】 &#xff08;3&#xff09;添加JAVA_HOME环境变量JAVA_HO…

展台搭建的基本要求

一、选址及总平面布置 展厅人流量大&#xff0c;对选址和总平面布置的要求如下:展厅选址应位于市内或郊区交通便利的区域。大型展览馆应有足够的群众活动广场和停车面积 &#xff0c;并应有室外陈列场地。室外场地要考虑环境的绿化和美化。各功能分区之间联系方便又互不干扰。建…

实现LCM在docker之间的通信

目录 1.docker容器互联 新建网络 连接容器 2.设置环境变量 3.在两个docker之间实现通信 1.docker容器互联 新建网络 $ docker network create -d bridge test-net 连接容器 运行一个容器并连接到新建的 test-net 网络: $ docker run -itd --name lcm_1 --network tes…

极智项目 | 实战Paddle戴口罩检测

欢迎关注我的公众号 [极智视界]&#xff0c;获取我的更多项目分享 大家好&#xff0c;我是极智视界&#xff0c;本文来介绍 实战 Paddle 戴口罩检测项目。 本文介绍的 实战 Paddle 戴口罩检测项目&#xff0c;提供完整的可以一键执行的项目工程源码&#xff0c;获取方式有两个…

AI红娘开启约会新时代;网易云音乐Agent实践探索;微软生成式AI课程要点笔记;ComfyUI新手教程;图解RAG进阶技术 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f440; Perplexity 官宣 7360 万美元B轮融资&#xff0c;打造世界上最快最准确的答案平台 https://blog.perplexity.ai/blog/perplexity-rais…

yyds,4 个 Pandas 必备神器!

Pandas是我们日常处理表格数据最常用的包&#xff0c;但是对于数据分析来说&#xff0c;Pandas的DataFrame还不够直观。 今天我们将介绍4个和Pandas相关的Python包&#xff0c;可以将Pandas的DataFrame转换交互式表格&#xff0c;让我们可以直接在上面进行数据分析的操作。 P…

天洑软件与常州大学成立电子信息专业学位硕士研究生联合培养基地

2023年12月27日&#xff0c;天洑软件与常州大学微电子与控制工程学院成立电子信息专业学位硕士研究生联合培养基地&#xff0c;授牌及企业导师聘任仪式于常州大学西太湖校区隆重举办。天洑软件前瞻技术研究院院长张儒受邀与会。 开幕式上&#xff0c;微电子与控制工程学院党委书…
最新文章